@friggframework/devtools 2.0.0--canary.522.cbd3d5a.0 → 2.0.0--canary.517.21b69ac.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/.eslintrc.json +3 -0
  2. package/CHANGELOG.md +132 -0
  3. package/frigg-cli/README.md +1 -1
  4. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  5. package/frigg-cli/__tests__/unit/commands/install.test.js +17 -21
  6. package/frigg-cli/doctor-command/index.js +16 -17
  7. package/frigg-cli/index.js +6 -21
  8. package/frigg-cli/index.test.js +1 -7
  9. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  10. package/frigg-cli/init-command/index.js +1 -2
  11. package/frigg-cli/init-command/template-handler.js +3 -13
  12. package/frigg-cli/install-command/backend-js.js +3 -3
  13. package/frigg-cli/install-command/environment-variables.js +19 -16
  14. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  15. package/frigg-cli/install-command/index.js +9 -14
  16. package/frigg-cli/install-command/integration-file.js +3 -3
  17. package/frigg-cli/install-command/logger.js +12 -0
  18. package/frigg-cli/install-command/validate-package.js +9 -5
  19. package/frigg-cli/jest.config.js +1 -4
  20. package/frigg-cli/repair-command/index.js +128 -101
  21. package/frigg-cli/start-command/index.js +2 -246
  22. package/frigg-cli/ui-command/index.js +36 -58
  23. package/frigg-cli/utils/repo-detection.js +37 -85
  24. package/infrastructure/docs/iam-policy-templates.md +1 -1
  25. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  26. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  27. package/infrastructure/domains/shared/cloudformation-discovery.test.js +7 -4
  28. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  29. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  30. package/infrastructure/domains/shared/utilities/base-definition-factory.js +2 -25
  31. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  32. package/infrastructure/infrastructure-composer.test.js +2 -2
  33. package/layers/prisma/.build-complete +3 -0
  34. package/layers/prisma/nodejs/package.json +8 -0
  35. package/management-ui/.eslintrc.js +22 -0
  36. package/management-ui/README.md +109 -245
  37. package/management-ui/components.json +21 -0
  38. package/management-ui/docs/phase2-integration-guide.md +320 -0
  39. package/management-ui/index.html +13 -0
  40. package/management-ui/package.json +76 -0
  41. package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
  42. package/management-ui/postcss.config.js +6 -0
  43. package/management-ui/server/api/backend.js +256 -0
  44. package/management-ui/server/api/cli.js +315 -0
  45. package/management-ui/server/api/codegen.js +663 -0
  46. package/management-ui/server/api/connections.js +857 -0
  47. package/management-ui/server/api/discovery.js +185 -0
  48. package/management-ui/server/api/environment/index.js +1 -0
  49. package/management-ui/server/api/environment/router.js +378 -0
  50. package/management-ui/server/api/environment.js +328 -0
  51. package/management-ui/server/api/integrations.js +876 -0
  52. package/management-ui/server/api/logs.js +248 -0
  53. package/management-ui/server/api/monitoring.js +282 -0
  54. package/management-ui/server/api/open-ide.js +31 -0
  55. package/management-ui/server/api/project.js +1029 -0
  56. package/management-ui/server/api/users/sessions.js +371 -0
  57. package/management-ui/server/api/users/simulation.js +254 -0
  58. package/management-ui/server/api/users.js +362 -0
  59. package/management-ui/server/api-contract.md +275 -0
  60. package/management-ui/server/index.js +873 -0
  61. package/management-ui/server/middleware/errorHandler.js +93 -0
  62. package/management-ui/server/middleware/security.js +32 -0
  63. package/management-ui/server/processManager.js +296 -0
  64. package/management-ui/server/server.js +346 -0
  65. package/management-ui/server/services/aws-monitor.js +413 -0
  66. package/management-ui/server/services/npm-registry.js +347 -0
  67. package/management-ui/server/services/template-engine.js +538 -0
  68. package/management-ui/server/utils/cliIntegration.js +220 -0
  69. package/management-ui/server/utils/environment/auditLogger.js +471 -0
  70. package/management-ui/server/utils/environment/awsParameterStore.js +275 -0
  71. package/management-ui/server/utils/environment/encryption.js +278 -0
  72. package/management-ui/server/utils/environment/envFileManager.js +286 -0
  73. package/management-ui/server/utils/import-commonjs.js +28 -0
  74. package/management-ui/server/utils/response.js +83 -0
  75. package/management-ui/server/websocket/handler.js +325 -0
  76. package/management-ui/src/App.jsx +25 -0
  77. package/management-ui/src/assets/FriggLogo.svg +1 -0
  78. package/management-ui/src/components/AppRouter.jsx +65 -0
  79. package/management-ui/src/components/Button.jsx +70 -0
  80. package/management-ui/src/components/Card.jsx +97 -0
  81. package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
  82. package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
  83. package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
  84. package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
  85. package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
  86. package/management-ui/src/components/ErrorBoundary.jsx +73 -0
  87. package/management-ui/src/components/IntegrationCard.jsx +481 -0
  88. package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
  89. package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
  90. package/management-ui/src/components/IntegrationStatus.jsx +336 -0
  91. package/management-ui/src/components/Layout.jsx +716 -0
  92. package/management-ui/src/components/LoadingSpinner.jsx +113 -0
  93. package/management-ui/src/components/RepositoryPicker.jsx +248 -0
  94. package/management-ui/src/components/SessionMonitor.jsx +350 -0
  95. package/management-ui/src/components/StatusBadge.jsx +208 -0
  96. package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
  97. package/management-ui/src/components/UserSimulation.jsx +327 -0
  98. package/management-ui/src/components/Welcome.jsx +434 -0
  99. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
  100. package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
  101. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
  102. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
  103. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
  104. package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
  105. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
  106. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
  107. package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
  108. package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
  109. package/management-ui/src/components/codegen/index.js +10 -0
  110. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
  111. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
  112. package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
  113. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
  114. package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
  115. package/management-ui/src/components/connections/index.js +5 -0
  116. package/management-ui/src/components/index.js +21 -0
  117. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
  118. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
  119. package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
  120. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
  121. package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
  122. package/management-ui/src/components/monitoring/index.js +6 -0
  123. package/management-ui/src/components/monitoring/monitoring.css +218 -0
  124. package/management-ui/src/components/theme-provider.jsx +52 -0
  125. package/management-ui/src/components/theme-toggle.jsx +39 -0
  126. package/management-ui/src/components/ui/badge.tsx +36 -0
  127. package/management-ui/src/components/ui/button.test.jsx +56 -0
  128. package/management-ui/src/components/ui/button.tsx +57 -0
  129. package/management-ui/src/components/ui/card.tsx +76 -0
  130. package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
  131. package/management-ui/src/components/ui/select.tsx +157 -0
  132. package/management-ui/src/components/ui/skeleton.jsx +15 -0
  133. package/management-ui/src/hooks/useFrigg.jsx +387 -0
  134. package/management-ui/src/hooks/useSocket.jsx +58 -0
  135. package/management-ui/src/index.css +193 -0
  136. package/management-ui/src/lib/utils.ts +6 -0
  137. package/management-ui/src/main.jsx +10 -0
  138. package/management-ui/src/pages/CodeGeneration.jsx +14 -0
  139. package/management-ui/src/pages/Connections.jsx +252 -0
  140. package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
  141. package/management-ui/src/pages/Dashboard.jsx +311 -0
  142. package/management-ui/src/pages/Environment.jsx +314 -0
  143. package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
  144. package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
  145. package/management-ui/src/pages/IntegrationTest.jsx +742 -0
  146. package/management-ui/src/pages/Integrations.jsx +253 -0
  147. package/management-ui/src/pages/Monitoring.jsx +17 -0
  148. package/management-ui/src/pages/Simulation.jsx +155 -0
  149. package/management-ui/src/pages/Users.jsx +492 -0
  150. package/management-ui/src/services/api.js +41 -0
  151. package/management-ui/src/services/apiModuleService.js +193 -0
  152. package/management-ui/src/services/websocket-handlers.js +120 -0
  153. package/management-ui/src/test/api/project.test.js +273 -0
  154. package/management-ui/src/test/components/Welcome.test.jsx +378 -0
  155. package/management-ui/src/test/mocks/server.js +178 -0
  156. package/management-ui/src/test/setup.js +61 -0
  157. package/management-ui/src/test/utils/test-utils.jsx +134 -0
  158. package/management-ui/src/utils/repository.js +98 -0
  159. package/management-ui/src/utils/repository.test.js +118 -0
  160. package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
  161. package/management-ui/tailwind.config.js +63 -0
  162. package/management-ui/tsconfig.json +37 -0
  163. package/management-ui/tsconfig.node.json +10 -0
  164. package/management-ui/vite.config.js +26 -0
  165. package/management-ui/vitest.config.js +38 -0
  166. package/package.json +7 -17
  167. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  168. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  169. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  170. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  171. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  172. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  173. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  174. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  175. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  176. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -430
  177. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  178. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  179. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  180. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  181. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  182. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  183. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  184. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  185. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  186. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  187. package/frigg-cli/container.js +0 -172
  188. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  189. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  190. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  191. package/frigg-cli/domain/entities/Integration.js +0 -198
  192. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  193. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  194. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  195. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  196. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  197. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  198. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  199. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  200. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  201. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  202. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  203. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  204. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  205. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  206. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  207. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  208. package/frigg-cli/package-lock.json +0 -16226
  209. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  210. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  211. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  212. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  213. package/frigg-cli/templates/backend/.env.example +0 -62
  214. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  215. package/frigg-cli/templates/backend/.prettierrc +0 -6
  216. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  217. package/frigg-cli/templates/backend/index.js +0 -96
  218. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  219. package/frigg-cli/templates/backend/jest.config.js +0 -17
  220. package/frigg-cli/templates/backend/package.json +0 -50
  221. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  222. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  223. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  224. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  225. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  226. package/frigg-cli/templates/backend/test/setup.js +0 -30
  227. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  228. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  229. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  230. package/frigg-cli/utils/output.js +0 -382
  231. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  232. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  233. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  234. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  235. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  236. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  237. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  238. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  239. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  240. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  241. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  242. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  243. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  244. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  245. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  246. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
  247. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
@@ -1,406 +0,0 @@
1
- /**
2
- * Tests for the init command and BackendFirstHandler
3
- * TDD: These tests define the expected behavior for frigg init
4
- */
5
-
6
- const path = require('path');
7
- const fs = require('fs-extra');
8
-
9
- // Mock dependencies before requiring the modules
10
- jest.mock('@inquirer/prompts', () => ({
11
- select: jest.fn(),
12
- confirm: jest.fn(),
13
- multiselect: jest.fn()
14
- }));
15
-
16
- jest.mock('../../../utils/npm-registry', () => ({
17
- searchApiModules: jest.fn().mockResolvedValue([]),
18
- getModulesByType: jest.fn().mockResolvedValue({})
19
- }));
20
-
21
- jest.mock('@friggframework/schemas', () => ({
22
- validateAppDefinition: jest.fn().mockReturnValue({ valid: true, errors: [] }),
23
- formatErrors: jest.fn().mockReturnValue('')
24
- }));
25
-
26
- const { select, confirm, multiselect } = require('@inquirer/prompts');
27
- const BackendFirstHandler = require('../../../init-command/backend-first-handler');
28
-
29
- describe('BackendFirstHandler', () => {
30
- let tempDir;
31
- let targetPath;
32
-
33
- beforeEach(async () => {
34
- // Create a real temporary directory for each test
35
- tempDir = global.TestHelpers.createTempDir();
36
- targetPath = path.join(tempDir, 'test-frigg-app');
37
-
38
- // Reset all mocks
39
- jest.clearAllMocks();
40
- });
41
-
42
- afterEach(async () => {
43
- // Clean up
44
- global.TestHelpers.cleanupTempDir(tempDir);
45
- });
46
-
47
- describe('constructor', () => {
48
- test('initializes with target path and options', () => {
49
- const handler = new BackendFirstHandler(targetPath, { verbose: true });
50
-
51
- expect(handler.targetPath).toBe(targetPath);
52
- expect(handler.appName).toBe('test-frigg-app');
53
- expect(handler.options.verbose).toBe(true);
54
- });
55
-
56
- test('sets templates directory correctly', () => {
57
- const handler = new BackendFirstHandler(targetPath);
58
-
59
- expect(handler.templatesDir).toContain('templates');
60
- });
61
- });
62
-
63
- describe('selectDeploymentMode', () => {
64
- test('returns mode from options if provided', async () => {
65
- const handler = new BackendFirstHandler(targetPath, { mode: 'standalone' });
66
-
67
- const mode = await handler.selectDeploymentMode();
68
-
69
- expect(mode).toBe('standalone');
70
- expect(select).not.toHaveBeenCalled();
71
- });
72
-
73
- test('prompts user if mode not provided', async () => {
74
- select.mockResolvedValue('embedded');
75
- const handler = new BackendFirstHandler(targetPath, {});
76
-
77
- const mode = await handler.selectDeploymentMode();
78
-
79
- expect(mode).toBe('embedded');
80
- expect(select).toHaveBeenCalledWith(expect.objectContaining({
81
- message: expect.stringContaining('deploy')
82
- }));
83
- });
84
- });
85
-
86
- describe('getProjectConfiguration', () => {
87
- test('collects all required configuration options', async () => {
88
- const handler = new BackendFirstHandler(targetPath, { frontend: false });
89
-
90
- // Mock all prompts in correct order
91
- // 1. appPurpose
92
- select.mockResolvedValueOnce('own-app');
93
- // 2. needsCustomApiModule (only asked when appPurpose === 'own-app')
94
- confirm.mockResolvedValueOnce(true);
95
- // 3. includeIntegrations
96
- confirm.mockResolvedValueOnce(false);
97
- // 4. serverlessProvider (only for standalone)
98
- select.mockResolvedValueOnce('aws');
99
- // 5. installDependencies
100
- confirm.mockResolvedValueOnce(true);
101
- // 6. initializeGit
102
- confirm.mockResolvedValueOnce(true);
103
-
104
- const config = await handler.getProjectConfiguration('standalone');
105
-
106
- expect(config.deploymentMode).toBe('standalone');
107
- expect(config.appPurpose).toBe('own-app');
108
- expect(config.needsCustomApiModule).toBe(true);
109
- expect(config.installDependencies).toBe(true);
110
- expect(config.initializeGit).toBe(true);
111
- });
112
-
113
- test('asks about demo frontend when not disabled', async () => {
114
- const handler = new BackendFirstHandler(targetPath, { frontend: undefined });
115
-
116
- // Mock prompts in correct order:
117
- // 1. appPurpose
118
- select.mockResolvedValueOnce('exploring');
119
- // 2. includeIntegrations
120
- confirm.mockResolvedValueOnce(false);
121
- // 3. includeDemoFrontend (asked when frontend !== false)
122
- confirm.mockResolvedValueOnce(true);
123
- // 4. frontendFramework (asked when includeDemoFrontend is true)
124
- select.mockResolvedValueOnce('react');
125
- // 5. demoAuthMode (asked when includeDemoFrontend is true)
126
- select.mockResolvedValueOnce('mock');
127
- // 6. serverlessProvider (for standalone mode)
128
- select.mockResolvedValueOnce('local');
129
- // 7. installDependencies
130
- confirm.mockResolvedValueOnce(true);
131
- // 8. initializeGit
132
- confirm.mockResolvedValueOnce(true);
133
-
134
- const config = await handler.getProjectConfiguration('standalone');
135
-
136
- expect(config.includeDemoFrontend).toBe(true);
137
- expect(config.frontendFramework).toBe('react');
138
- expect(config.demoAuthMode).toBe('mock');
139
- });
140
-
141
- test('skips demo frontend question when frontend is false', async () => {
142
- const handler = new BackendFirstHandler(targetPath, { frontend: false });
143
-
144
- select.mockResolvedValueOnce('exploring') // appPurpose
145
- .mockResolvedValueOnce('local'); // serverlessProvider
146
- confirm.mockResolvedValueOnce(false) // includeIntegrations
147
- .mockResolvedValueOnce(true) // installDependencies
148
- .mockResolvedValueOnce(true); // initializeGit
149
-
150
- const config = await handler.getProjectConfiguration('standalone');
151
-
152
- expect(config.includeDemoFrontend).toBeUndefined();
153
- });
154
- });
155
-
156
- describe('createProject', () => {
157
- test('creates target directory if it does not exist', async () => {
158
- const handler = new BackendFirstHandler(targetPath, { force: true });
159
-
160
- // Create minimal config
161
- const config = {
162
- deploymentMode: 'standalone',
163
- installDependencies: false,
164
- initializeGit: false,
165
- serverlessProvider: 'local'
166
- };
167
-
168
- // Mock that templates exist
169
- const templatesDir = handler.templatesDir;
170
- const backendTemplateDir = path.join(templatesDir, 'backend');
171
-
172
- // We expect the directory to be created
173
- await handler.ensureSafeDirectory();
174
-
175
- expect(fs.existsSync(targetPath)).toBe(true);
176
- });
177
-
178
- test('throws error when directory is not empty without force flag', async () => {
179
- // Create target directory with a file in it
180
- await fs.ensureDir(targetPath);
181
- await fs.writeFile(path.join(targetPath, 'existing-file.js'), 'content');
182
-
183
- const handler = new BackendFirstHandler(targetPath, { force: false });
184
-
185
- await expect(handler.ensureSafeDirectory())
186
- .rejects
187
- .toThrow('Directory not empty');
188
- });
189
-
190
- test('allows non-empty directory with force flag', async () => {
191
- // Create target directory with a file in it
192
- await fs.ensureDir(targetPath);
193
- await fs.writeFile(path.join(targetPath, 'existing-file.js'), 'content');
194
-
195
- const handler = new BackendFirstHandler(targetPath, { force: true });
196
-
197
- // Should not throw
198
- await handler.ensureSafeDirectory();
199
-
200
- expect(fs.existsSync(targetPath)).toBe(true);
201
- });
202
-
203
- test('allows allowed files without force flag', async () => {
204
- // Create target directory with allowed files
205
- await fs.ensureDir(targetPath);
206
- await fs.writeFile(path.join(targetPath, '.git'), '');
207
- await fs.writeFile(path.join(targetPath, '.gitignore'), '');
208
- await fs.writeFile(path.join(targetPath, 'README.md'), '');
209
-
210
- const handler = new BackendFirstHandler(targetPath, { force: false });
211
-
212
- // Should not throw for allowed files
213
- await handler.ensureSafeDirectory();
214
-
215
- expect(fs.existsSync(targetPath)).toBe(true);
216
- });
217
- });
218
-
219
- describe('createStandaloneProject', () => {
220
- // Note: These tests rely on the real backend template in templates/backend
221
- // If the template doesn't exist, tests will be skipped
222
-
223
- test('creates package.json with correct scripts', async () => {
224
- const handler = new BackendFirstHandler(targetPath, { force: true });
225
- await fs.ensureDir(targetPath);
226
-
227
- const config = {
228
- serverlessProvider: 'aws',
229
- starterIntegrations: [],
230
- installDependencies: false
231
- };
232
-
233
- await handler.createStandaloneProject(config);
234
-
235
- const packageJson = await fs.readJSON(path.join(targetPath, 'package.json'));
236
-
237
- expect(packageJson.name).toBe('test-frigg-app');
238
- expect(packageJson.scripts).toHaveProperty('start');
239
- expect(packageJson.scripts).toHaveProperty('build');
240
- expect(packageJson.scripts).toHaveProperty('deploy');
241
- expect(packageJson.scripts).toHaveProperty('test');
242
- });
243
-
244
- test('adds selected integrations as dependencies', async () => {
245
- const handler = new BackendFirstHandler(targetPath, { force: true });
246
- await fs.ensureDir(targetPath);
247
-
248
- const config = {
249
- serverlessProvider: 'aws',
250
- starterIntegrations: ['salesforce', 'hubspot'],
251
- installDependencies: false
252
- };
253
-
254
- await handler.createStandaloneProject(config);
255
-
256
- const packageJson = await fs.readJSON(path.join(targetPath, 'package.json'));
257
-
258
- expect(packageJson.dependencies).toHaveProperty('@friggframework/api-module-salesforce');
259
- expect(packageJson.dependencies).toHaveProperty('@friggframework/api-module-hubspot');
260
- });
261
-
262
- test('includes @friggframework/core as dependency', async () => {
263
- const handler = new BackendFirstHandler(targetPath, { force: true });
264
- await fs.ensureDir(targetPath);
265
-
266
- const config = {
267
- serverlessProvider: 'local',
268
- starterIntegrations: [],
269
- installDependencies: false
270
- };
271
-
272
- await handler.createStandaloneProject(config);
273
-
274
- const packageJson = await fs.readJSON(path.join(targetPath, 'package.json'));
275
-
276
- expect(packageJson.dependencies).toHaveProperty('@friggframework/core');
277
- });
278
- });
279
-
280
- describe('createEmbeddedProject', () => {
281
- // Note: These tests rely on the real backend template in templates/backend
282
- // If the template doesn't exist, tests will be skipped
283
-
284
- test('creates frigg-integration subdirectory', async () => {
285
- const handler = new BackendFirstHandler(targetPath, { force: true });
286
- await fs.ensureDir(targetPath);
287
-
288
- const config = {
289
- installDependencies: false
290
- };
291
-
292
- await handler.createEmbeddedProject(config);
293
-
294
- const integrationDir = path.join(targetPath, 'frigg-integration');
295
- expect(fs.existsSync(integrationDir)).toBe(true);
296
- });
297
-
298
- test('creates FRIGG_INTEGRATION.md guide', async () => {
299
- const handler = new BackendFirstHandler(targetPath, { force: true });
300
- await fs.ensureDir(targetPath);
301
-
302
- const config = {
303
- installDependencies: false
304
- };
305
-
306
- await handler.createEmbeddedProject(config);
307
-
308
- const guidePath = path.join(targetPath, 'FRIGG_INTEGRATION.md');
309
- expect(fs.existsSync(guidePath)).toBe(true);
310
-
311
- const content = await fs.readFile(guidePath, 'utf8');
312
- expect(content).toContain('# Frigg Integration Guide');
313
- expect(content).toContain('@friggframework/core');
314
- });
315
- });
316
-
317
- describe('getIntegrationClassName', () => {
318
- test('converts known integrations to class names', () => {
319
- const handler = new BackendFirstHandler(targetPath);
320
-
321
- expect(handler.getIntegrationClassName('salesforce')).toBe('SalesforceIntegration');
322
- expect(handler.getIntegrationClassName('hubspot')).toBe('HubSpotIntegration');
323
- expect(handler.getIntegrationClassName('slack')).toBe('SlackIntegration');
324
- expect(handler.getIntegrationClassName('google-sheets')).toBe('GoogleSheetsIntegration');
325
- });
326
-
327
- test('generates class name for unknown integrations', () => {
328
- const handler = new BackendFirstHandler(targetPath);
329
-
330
- expect(handler.getIntegrationClassName('custom-api')).toBe('Custom-apiIntegration');
331
- });
332
- });
333
-
334
- describe('isUsingYarn', () => {
335
- test('returns true when npm_config_user_agent contains yarn', () => {
336
- const originalEnv = process.env.npm_config_user_agent;
337
- process.env.npm_config_user_agent = 'yarn/1.22.0';
338
-
339
- const handler = new BackendFirstHandler(targetPath);
340
-
341
- expect(handler.isUsingYarn()).toBe(true);
342
-
343
- process.env.npm_config_user_agent = originalEnv;
344
- });
345
-
346
- test('returns false when using npm', () => {
347
- const originalEnv = process.env.npm_config_user_agent;
348
- process.env.npm_config_user_agent = 'npm/8.0.0';
349
-
350
- const handler = new BackendFirstHandler(targetPath);
351
-
352
- expect(handler.isUsingYarn()).toBe(false);
353
-
354
- process.env.npm_config_user_agent = originalEnv;
355
- });
356
- });
357
- });
358
-
359
- describe('initCommand', () => {
360
- const { initCommand } = require('../../../init-command');
361
- let tempDir;
362
-
363
- beforeEach(() => {
364
- tempDir = global.TestHelpers.createTempDir();
365
- jest.clearAllMocks();
366
- });
367
-
368
- afterEach(() => {
369
- global.TestHelpers.cleanupTempDir(tempDir);
370
- });
371
-
372
- test('validates project name - uppercase names are allowed in npm', async () => {
373
- // Note: npm actually allows uppercase names now, they get lowercased
374
- // The validate-npm-package-name package allows uppercase
375
- const validName = path.join(tempDir, 'Valid-Name');
376
-
377
- // Mock prompts to allow the command to proceed
378
- select.mockResolvedValue('standalone');
379
- confirm.mockResolvedValue(false);
380
-
381
- // This should not throw for package name validation
382
- // It may fail for other reasons like missing templates
383
- try {
384
- await initCommand(validName, { mode: 'standalone' });
385
- } catch (e) {
386
- // Expected to fail for missing template, not for name validation
387
- expect(e.message).not.toContain('npm naming restrictions');
388
- }
389
- });
390
-
391
- test('checks Node version', async () => {
392
- const projectPath = path.join(tempDir, 'valid-project');
393
-
394
- // Mock prompts to return quickly
395
- select.mockResolvedValue('standalone');
396
- confirm.mockResolvedValue(false);
397
-
398
- // This should not throw for invalid Node version (just warn)
399
- // The test validates checkNodeVersion is called
400
- try {
401
- await initCommand(projectPath, { mode: 'standalone' });
402
- } catch (e) {
403
- // May fail for other reasons, but shouldn't throw for Node version
404
- }
405
- });
406
- });
@@ -1,275 +0,0 @@
1
- /**
2
- * Unit tests for frigg repair command
3
- * Tests repair workflow orchestration and output usage
4
- */
5
-
6
- // Mock all external dependencies
7
- jest.mock('../../../utils/output');
8
- jest.mock('../../../repair-command/index.js', () => {
9
- const actualModule = jest.requireActual('../../../repair-command/index.js');
10
- return actualModule;
11
- }, { virtual: false });
12
-
13
- const output = require('../../../utils/output');
14
-
15
- describe('Repair Command - Output Integration', () => {
16
- beforeEach(() => {
17
- jest.clearAllMocks();
18
-
19
- // Setup output mocks
20
- output.success = jest.fn();
21
- output.error = jest.fn();
22
- output.info = jest.fn();
23
- output.warn = jest.fn();
24
- output.log = jest.fn();
25
- output.confirm = jest.fn();
26
- });
27
-
28
- describe('Output method usage', () => {
29
- test('should use output.success for successful operations', () => {
30
- // Test that success messages use output.success
31
- output.success(' No orphaned resources to import');
32
-
33
- expect(output.success).toHaveBeenCalledWith(
34
- expect.stringContaining('No orphaned resources')
35
- );
36
- });
37
-
38
- test('should use output.error for error messages', () => {
39
- // Test that errors use output.error
40
- const error = new Error('Stack not found');
41
- output.error('An error occurred:', error);
42
-
43
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
44
- });
45
-
46
- test('should use output.info for informational messages', () => {
47
- // Test that info messages use output.info with emoji
48
- output.info('🔍 Analyzing stack health...');
49
-
50
- expect(output.info).toHaveBeenCalledWith(
51
- expect.stringContaining('Analyzing stack')
52
- );
53
- });
54
-
55
- test('should use output.warn for warnings', () => {
56
- // Test that warnings use output.warn
57
- output.warn('️ Build template not found');
58
-
59
- expect(output.warn).toHaveBeenCalledWith(
60
- expect.stringContaining('Build template not found')
61
- );
62
- });
63
-
64
- test('should use output.log for general messages', () => {
65
- // Test that general messages use output.log
66
- output.log(' • serverless package');
67
-
68
- expect(output.log).toHaveBeenCalledWith(
69
- expect.stringContaining('serverless package')
70
- );
71
- });
72
-
73
- test('should use output.confirm for user confirmations', async () => {
74
- // Test that confirmations use output.confirm
75
- output.confirm.mockResolvedValue(true);
76
-
77
- const result = await output.confirm('Import 5 orphaned resource(s)?');
78
-
79
- expect(output.confirm).toHaveBeenCalledWith(
80
- expect.stringContaining('Import')
81
- );
82
- expect(result).toBe(true);
83
- });
84
- });
85
-
86
- describe('Error handling scenarios', () => {
87
- test('should handle and report stack not found errors', () => {
88
- const error = new Error('Stack does not exist');
89
- output.error('An error occurred:', error);
90
-
91
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
92
- });
93
-
94
- test('should handle and report import validation errors', () => {
95
- output.log('\nValidation errors:');
96
- output.log(' • Resource1: Invalid property');
97
-
98
- expect(output.log).toHaveBeenCalledWith('\nValidation errors:');
99
- expect(output.log).toHaveBeenCalledWith(expect.stringContaining('Invalid property'));
100
- });
101
-
102
- test('should handle and report AWS API errors', () => {
103
- const error = new Error('AccessDenied: Insufficient permissions');
104
- output.error('An error occurred:', error);
105
-
106
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
107
- });
108
- });
109
-
110
- describe('User workflow scenarios', () => {
111
- test('should report when no orphaned resources are found', () => {
112
- output.success(' No orphaned resources to import');
113
-
114
- expect(output.success).toHaveBeenCalled();
115
- expect(output.success).toHaveBeenCalledWith(
116
- expect.stringContaining('No orphaned resources')
117
- );
118
- });
119
-
120
- test('should list orphaned resources before import', () => {
121
- output.info('📦 Found 3 orphaned resource(s) to import:');
122
- output.log(' 1. AWS::Lambda::Function - my-function');
123
- output.log(' 2. AWS::S3::Bucket - my-bucket');
124
- output.log(' 3. AWS::DynamoDB::Table - my-table');
125
-
126
- expect(output.info).toHaveBeenCalledWith(
127
- expect.stringMatching(/Found \d+ orphaned/)
128
- );
129
- expect(output.log).toHaveBeenCalledTimes(3);
130
- });
131
-
132
- test('should warn when build template is missing', () => {
133
- output.warn('️ Build template not found. Generating sequential logical IDs (not recommended).');
134
- output.log(' Run one of the following to generate build template:');
135
- output.log(' • serverless package');
136
-
137
- expect(output.warn).toHaveBeenCalledWith(
138
- expect.stringContaining('Build template not found')
139
- );
140
- expect(output.log).toHaveBeenCalledWith(
141
- expect.stringContaining('serverless package')
142
- );
143
- });
144
-
145
- test('should confirm before performing import', async () => {
146
- output.confirm.mockResolvedValue(true);
147
-
148
- const confirmed = await output.confirm('Import 5 orphaned resource(s) with sequential IDs?');
149
-
150
- expect(output.confirm).toHaveBeenCalled();
151
- expect(confirmed).toBe(true);
152
- });
153
-
154
- test('should handle user cancellation gracefully', async () => {
155
- output.confirm.mockResolvedValue(false);
156
-
157
- const confirmed = await output.confirm('Import resources?');
158
- if (!confirmed) {
159
- output.log('Import cancelled');
160
- }
161
-
162
- expect(output.confirm).toHaveBeenCalled();
163
- expect(output.log).toHaveBeenCalledWith('Import cancelled');
164
- });
165
-
166
- test('should report successful import results', () => {
167
- output.success(' Successfully imported 5 resource(s)');
168
-
169
- expect(output.success).toHaveBeenCalledWith(
170
- expect.stringMatching(/Successfully imported \d+/)
171
- );
172
- });
173
- });
174
-
175
- describe('Repair workflow stages', () => {
176
- test('should progress through health check stage', () => {
177
- output.info('🏥 Running health check on stack...');
178
-
179
- expect(output.info).toHaveBeenCalledWith(
180
- expect.stringContaining('health check')
181
- );
182
- });
183
-
184
- test('should progress through import stage', () => {
185
- output.info('🔧 Importing resources with sequential IDs...');
186
-
187
- expect(output.info).toHaveBeenCalledWith(
188
- expect.stringContaining('Importing resources')
189
- );
190
- });
191
-
192
- test('should progress through reconciliation stage', () => {
193
- output.info('🔄 Reconciling property drift...');
194
-
195
- expect(output.info).toHaveBeenCalledWith(
196
- expect.stringContaining('Reconciling')
197
- );
198
- });
199
-
200
- test('should report completion with summary', () => {
201
- output.success(' Repair completed successfully');
202
- output.log('\nSummary:');
203
- output.log(' • Imported: 5 resources');
204
- output.log(' • Reconciled: 3 properties');
205
-
206
- expect(output.success).toHaveBeenCalledWith(
207
- expect.stringContaining('completed successfully')
208
- );
209
- expect(output.log).toHaveBeenCalledWith('\nSummary:');
210
- });
211
- });
212
-
213
- describe('Output consistency', () => {
214
- test('should not use console.log directly', () => {
215
- // Verify that all logging goes through output module
216
- const consoleLogSpy = jest.spyOn(console, 'log');
217
-
218
- output.log('Test message');
219
-
220
- // output.log may call console.log internally, but command code shouldn't
221
- expect(output.log).toHaveBeenCalled();
222
-
223
- consoleLogSpy.mockRestore();
224
- });
225
-
226
- test('should not use console.error directly', () => {
227
- // Verify that all errors go through output module
228
- const consoleErrorSpy = jest.spyOn(console, 'error');
229
-
230
- const error = new Error('Test error');
231
- output.error('An error occurred:', error);
232
-
233
- // output.error may call console.error internally, but command code shouldn't
234
- expect(output.error).toHaveBeenCalled();
235
-
236
- consoleErrorSpy.mockRestore();
237
- });
238
-
239
- test('should use consistent emoji patterns', () => {
240
- // Verify emoji usage follows patterns
241
- output.success(' Success message'); // ✓ or ✅
242
- output.error(' Error message'); // ✗ or ❌
243
- output.warn('️ Warning message'); // ⚠️
244
- output.info('🔍 Info message'); // Various info emojis
245
-
246
- expect(output.success).toHaveBeenCalled();
247
- expect(output.error).toHaveBeenCalled();
248
- expect(output.warn).toHaveBeenCalled();
249
- expect(output.info).toHaveBeenCalled();
250
- });
251
- });
252
-
253
- describe('Migration verification', () => {
254
- test('should have migrated all console.log calls', () => {
255
- // This test verifies the migration was complete
256
- // In the actual command file, there should be 0 console.log references
257
- expect(output.log).toBeDefined();
258
- expect(output.info).toBeDefined();
259
- expect(output.success).toBeDefined();
260
- });
261
-
262
- test('should have migrated all console.error calls', () => {
263
- // This test verifies the migration was complete
264
- // In the actual command file, there should be 0 console.error references
265
- expect(output.error).toBeDefined();
266
- expect(output.warn).toBeDefined();
267
- });
268
-
269
- test('should have migrated readline confirm to output.confirm', () => {
270
- // This test verifies readline was replaced with output.confirm
271
- expect(output.confirm).toBeDefined();
272
- expect(typeof output.confirm).toBe('function');
273
- });
274
- });
275
- });