@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.47

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 (212) hide show
  1. package/infrastructure/ARCHITECTURE.md +487 -0
  2. package/infrastructure/HEALTH.md +468 -0
  3. package/infrastructure/README.md +51 -0
  4. package/infrastructure/__tests__/postgres-config.test.js +914 -0
  5. package/infrastructure/__tests__/template-generation.test.js +687 -0
  6. package/infrastructure/create-frigg-infrastructure.js +1 -1
  7. package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
  8. package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
  9. package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
  10. package/infrastructure/domains/database/aurora-builder.js +809 -0
  11. package/infrastructure/domains/database/aurora-builder.test.js +950 -0
  12. package/infrastructure/domains/database/aurora-discovery.js +87 -0
  13. package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
  14. package/infrastructure/domains/database/aurora-resolver.js +210 -0
  15. package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
  16. package/infrastructure/domains/database/migration-builder.js +695 -0
  17. package/infrastructure/domains/database/migration-builder.test.js +294 -0
  18. package/infrastructure/domains/database/migration-resolver.js +163 -0
  19. package/infrastructure/domains/database/migration-resolver.test.js +337 -0
  20. package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
  21. package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
  22. package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
  23. package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
  24. package/infrastructure/domains/health/application/ports/index.js +26 -0
  25. package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
  26. package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
  27. package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
  28. package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
  29. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
  30. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
  31. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
  32. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
  33. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
  34. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
  35. package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
  36. package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
  37. package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
  38. package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
  39. package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
  40. package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
  41. package/infrastructure/domains/health/domain/entities/issue.js +299 -0
  42. package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
  43. package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
  44. package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
  45. package/infrastructure/domains/health/domain/entities/resource.js +159 -0
  46. package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
  47. package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
  48. package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
  49. package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
  50. package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
  51. package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
  52. package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
  53. package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
  54. package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
  55. package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
  56. package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
  57. package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
  58. package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
  59. package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
  60. package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
  61. package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
  62. package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
  63. package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
  64. package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
  65. package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
  66. package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
  67. package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
  68. package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
  69. package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
  70. package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
  71. package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
  72. package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
  73. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
  74. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
  75. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
  76. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
  77. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
  78. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
  79. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
  80. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
  81. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
  82. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
  83. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
  84. package/infrastructure/domains/integration/integration-builder.js +397 -0
  85. package/infrastructure/domains/integration/integration-builder.test.js +593 -0
  86. package/infrastructure/domains/integration/integration-resolver.js +170 -0
  87. package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
  88. package/infrastructure/domains/integration/websocket-builder.js +69 -0
  89. package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
  90. package/infrastructure/domains/networking/vpc-builder.js +1829 -0
  91. package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
  92. package/infrastructure/domains/networking/vpc-discovery.js +177 -0
  93. package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
  94. package/infrastructure/domains/networking/vpc-resolver.js +324 -0
  95. package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
  96. package/infrastructure/domains/parameters/ssm-builder.js +79 -0
  97. package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
  98. package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
  99. package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
  100. package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
  101. package/infrastructure/domains/security/kms-builder.js +366 -0
  102. package/infrastructure/domains/security/kms-builder.test.js +374 -0
  103. package/infrastructure/domains/security/kms-discovery.js +80 -0
  104. package/infrastructure/domains/security/kms-discovery.test.js +177 -0
  105. package/infrastructure/domains/security/kms-resolver.js +96 -0
  106. package/infrastructure/domains/security/kms-resolver.test.js +216 -0
  107. package/infrastructure/domains/shared/base-builder.js +112 -0
  108. package/infrastructure/domains/shared/base-resolver.js +186 -0
  109. package/infrastructure/domains/shared/base-resolver.test.js +305 -0
  110. package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
  111. package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
  112. package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
  113. package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
  114. package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
  115. package/infrastructure/domains/shared/environment-builder.js +119 -0
  116. package/infrastructure/domains/shared/environment-builder.test.js +247 -0
  117. package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
  118. package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
  119. package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
  120. package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
  121. package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
  122. package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
  123. package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
  124. package/infrastructure/domains/shared/resource-discovery.js +192 -0
  125. package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
  126. package/infrastructure/domains/shared/types/app-definition.js +205 -0
  127. package/infrastructure/domains/shared/types/discovery-result.js +106 -0
  128. package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
  129. package/infrastructure/domains/shared/types/index.js +46 -0
  130. package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
  131. package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
  132. package/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
  133. package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
  134. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
  135. package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
  136. package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
  137. package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
  138. package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
  139. package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
  140. package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
  141. package/infrastructure/esbuild.config.js +53 -0
  142. package/infrastructure/infrastructure-composer.js +87 -0
  143. package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
  144. package/infrastructure/scripts/build-prisma-layer.js +553 -0
  145. package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
  146. package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
  147. package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
  148. package/layers/prisma/nodejs/package.json +8 -0
  149. package/management-ui/server/utils/cliIntegration.js +1 -1
  150. package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
  151. package/package.json +11 -11
  152. package/frigg-cli/.eslintrc.js +0 -141
  153. package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
  154. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
  155. package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
  156. package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
  157. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
  158. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
  159. package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
  160. package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
  161. package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
  162. package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
  163. package/frigg-cli/__tests__/utils/test-setup.js +0 -287
  164. package/frigg-cli/build-command/index.js +0 -65
  165. package/frigg-cli/db-setup-command/index.js +0 -193
  166. package/frigg-cli/deploy-command/index.js +0 -175
  167. package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
  168. package/frigg-cli/generate-command/azure-generator.js +0 -43
  169. package/frigg-cli/generate-command/gcp-generator.js +0 -47
  170. package/frigg-cli/generate-command/index.js +0 -332
  171. package/frigg-cli/generate-command/terraform-generator.js +0 -555
  172. package/frigg-cli/generate-iam-command.js +0 -118
  173. package/frigg-cli/index.js +0 -75
  174. package/frigg-cli/index.test.js +0 -158
  175. package/frigg-cli/init-command/backend-first-handler.js +0 -756
  176. package/frigg-cli/init-command/index.js +0 -93
  177. package/frigg-cli/init-command/template-handler.js +0 -143
  178. package/frigg-cli/install-command/backend-js.js +0 -33
  179. package/frigg-cli/install-command/commit-changes.js +0 -16
  180. package/frigg-cli/install-command/environment-variables.js +0 -127
  181. package/frigg-cli/install-command/environment-variables.test.js +0 -136
  182. package/frigg-cli/install-command/index.js +0 -54
  183. package/frigg-cli/install-command/install-package.js +0 -13
  184. package/frigg-cli/install-command/integration-file.js +0 -30
  185. package/frigg-cli/install-command/logger.js +0 -12
  186. package/frigg-cli/install-command/template.js +0 -90
  187. package/frigg-cli/install-command/validate-package.js +0 -75
  188. package/frigg-cli/jest.config.js +0 -124
  189. package/frigg-cli/package.json +0 -54
  190. package/frigg-cli/start-command/index.js +0 -149
  191. package/frigg-cli/start-command/start-command.test.js +0 -297
  192. package/frigg-cli/test/init-command.test.js +0 -180
  193. package/frigg-cli/test/npm-registry.test.js +0 -319
  194. package/frigg-cli/ui-command/index.js +0 -154
  195. package/frigg-cli/utils/app-resolver.js +0 -319
  196. package/frigg-cli/utils/backend-path.js +0 -25
  197. package/frigg-cli/utils/database-validator.js +0 -161
  198. package/frigg-cli/utils/error-messages.js +0 -257
  199. package/frigg-cli/utils/npm-registry.js +0 -167
  200. package/frigg-cli/utils/prisma-runner.js +0 -280
  201. package/frigg-cli/utils/process-manager.js +0 -199
  202. package/frigg-cli/utils/repo-detection.js +0 -405
  203. package/infrastructure/aws-discovery.js +0 -1176
  204. package/infrastructure/aws-discovery.test.js +0 -1220
  205. package/infrastructure/serverless-template.js +0 -2094
  206. /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
  207. /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
  208. /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
  209. /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
  210. /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
  211. /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
  212. /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
@@ -1,346 +0,0 @@
1
- /**
2
- * Test suite for ui command
3
- *
4
- * Tests the management UI startup functionality including:
5
- * - Repository detection and discovery
6
- * - Development mode (backend + frontend servers)
7
- * - Production mode (integrated server)
8
- * - Browser opening
9
- * - Error handling (port conflicts, missing repos)
10
- * - Process management
11
- */
12
-
13
- // Mock dependencies BEFORE requiring modules
14
- jest.mock('open', () => jest.fn());
15
- jest.mock('../../../utils/process-manager');
16
- jest.mock('../../../utils/repo-detection', () => ({
17
- getCurrentRepositoryInfo: jest.fn(),
18
- discoverFriggRepositories: jest.fn(),
19
- promptRepositorySelection: jest.fn(),
20
- formatRepositoryInfo: jest.fn()
21
- }));
22
- jest.mock('fs', () => ({
23
- existsSync: jest.fn()
24
- }));
25
-
26
- // Require after mocks
27
- const open = require('open');
28
- const ProcessManager = require('../../../utils/process-manager');
29
- const {
30
- getCurrentRepositoryInfo,
31
- discoverFriggRepositories,
32
- formatRepositoryInfo
33
- } = require('../../../utils/repo-detection');
34
- const { uiCommand } = require('../../../ui-command');
35
-
36
- describe('CLI Command: ui', () => {
37
- let consoleLogSpy;
38
- let consoleErrorSpy;
39
- let processExitSpy;
40
- let mockProcessManager;
41
- let originalEnv;
42
- let stdinResumeSpy;
43
-
44
- beforeEach(() => {
45
- jest.clearAllMocks();
46
-
47
- // Mock console methods
48
- consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
49
- consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
50
-
51
- // Mock process.exit to prevent actual exit
52
- processExitSpy = jest.spyOn(process, 'exit').mockImplementation();
53
-
54
- // Mock process.stdin.resume
55
- stdinResumeSpy = jest.spyOn(process.stdin, 'resume').mockImplementation();
56
-
57
- // Store and reset NODE_ENV
58
- originalEnv = process.env.NODE_ENV;
59
- delete process.env.NODE_ENV;
60
-
61
- // Setup ProcessManager mock
62
- mockProcessManager = {
63
- spawnProcess: jest.fn(),
64
- printStatus: jest.fn()
65
- };
66
- ProcessManager.mockImplementation(() => mockProcessManager);
67
-
68
- // Setup default repo-detection mocks
69
- getCurrentRepositoryInfo.mockResolvedValue({
70
- path: '/mock/frigg-repo',
71
- name: 'test-repo',
72
- currentSubPath: null
73
- });
74
- formatRepositoryInfo.mockReturnValue('test-repo');
75
- });
76
-
77
- afterEach(() => {
78
- consoleLogSpy.mockRestore();
79
- consoleErrorSpy.mockRestore();
80
- processExitSpy.mockRestore();
81
- stdinResumeSpy.mockRestore();
82
- process.env.NODE_ENV = originalEnv;
83
- });
84
-
85
- describe('Repository Detection', () => {
86
- it('should use specified repo path when provided', async () => {
87
- await uiCommand({ repo: '/custom/repo', port: 3001, open: false });
88
-
89
- expect(consoleLogSpy).toHaveBeenCalledWith(
90
- expect.stringContaining('Using specified repository')
91
- );
92
- });
93
-
94
- it('should detect current Frigg repository', async () => {
95
- await uiCommand({ port: 3001, open: false });
96
-
97
- expect(getCurrentRepositoryInfo).toHaveBeenCalled();
98
- expect(consoleLogSpy).toHaveBeenCalledWith(
99
- expect.stringContaining('Found Frigg repository')
100
- );
101
- });
102
-
103
- it('should show subdirectory when in subpath', async () => {
104
- getCurrentRepositoryInfo.mockResolvedValue({
105
- path: '/mock/frigg-repo',
106
- name: 'test-repo',
107
- currentSubPath: 'packages/backend'
108
- });
109
-
110
- await uiCommand({ port: 3001, open: false });
111
-
112
- expect(consoleLogSpy).toHaveBeenCalledWith(
113
- expect.stringContaining('Currently in subdirectory: packages/backend')
114
- );
115
- });
116
-
117
- it('should discover repos when not in Frigg repo', async () => {
118
- getCurrentRepositoryInfo.mockResolvedValue(null);
119
- discoverFriggRepositories.mockResolvedValue([
120
- { path: '/repos/frigg-1', name: 'frigg-1' },
121
- { path: '/repos/frigg-2', name: 'frigg-2' }
122
- ]);
123
-
124
- await uiCommand({ port: 3001, open: false });
125
-
126
- expect(discoverFriggRepositories).toHaveBeenCalled();
127
- expect(consoleLogSpy).toHaveBeenCalledWith(
128
- expect.stringContaining('Found 2 Frigg repositories')
129
- );
130
- });
131
-
132
- it('should exit when no repos found', async () => {
133
- getCurrentRepositoryInfo.mockResolvedValue(null);
134
- discoverFriggRepositories.mockResolvedValue([]);
135
-
136
- await uiCommand({ port: 3001, open: false });
137
-
138
- expect(consoleLogSpy).toHaveBeenCalledWith(
139
- expect.stringContaining('No Frigg repositories found')
140
- );
141
- expect(processExitSpy).toHaveBeenCalledWith(1);
142
- });
143
- });
144
-
145
- describe('Development Mode', () => {
146
- it('should spawn backend and frontend in dev mode', async () => {
147
- await uiCommand({ port: 3001, open: false, dev: true });
148
-
149
- expect(mockProcessManager.spawnProcess).toHaveBeenCalledTimes(2);
150
- expect(mockProcessManager.spawnProcess).toHaveBeenCalledWith(
151
- 'backend',
152
- 'npm',
153
- ['run', 'server'],
154
- expect.objectContaining({
155
- cwd: expect.stringContaining('management-ui'),
156
- env: expect.objectContaining({
157
- PORT: 3001,
158
- VITE_API_URL: 'http://localhost:3001'
159
- })
160
- })
161
- );
162
- expect(mockProcessManager.spawnProcess).toHaveBeenCalledWith(
163
- 'frontend',
164
- 'npm',
165
- ['run', 'dev'],
166
- expect.any(Object)
167
- );
168
- });
169
-
170
- it('should use default port 3001', async () => {
171
- await uiCommand({ open: false, dev: true });
172
-
173
- expect(mockProcessManager.spawnProcess).toHaveBeenCalledWith(
174
- expect.any(String),
175
- expect.any(String),
176
- expect.any(Array),
177
- expect.objectContaining({
178
- env: expect.objectContaining({ PORT: 3001 })
179
- })
180
- );
181
- });
182
-
183
- it('should use custom port when specified', async () => {
184
- await uiCommand({ port: 4000, open: false, dev: true });
185
-
186
- expect(mockProcessManager.spawnProcess).toHaveBeenCalledWith(
187
- expect.any(String),
188
- expect.any(String),
189
- expect.any(Array),
190
- expect.objectContaining({
191
- env: expect.objectContaining({
192
- PORT: 4000,
193
- VITE_API_URL: 'http://localhost:4000'
194
- })
195
- })
196
- );
197
- });
198
-
199
- it('should print status with correct URLs', async () => {
200
- await uiCommand({ port: 3001, open: false, dev: true });
201
-
202
- // Wait for startup delay (testing async behavior, not mocks)
203
- await new Promise(resolve => setTimeout(resolve, 2100));
204
-
205
- // Verify printStatus called with exact URLs
206
- expect(mockProcessManager.printStatus).toHaveBeenCalledWith(
207
- 'http://localhost:5173',
208
- 'http://localhost:3001',
209
- 'test-repo'
210
- );
211
- });
212
-
213
- it('should open browser when open=true', async () => {
214
- await uiCommand({ port: 3001, open: true, dev: true });
215
-
216
- // Wait for startup + browser delay (testing async behavior, not mocks)
217
- await new Promise(resolve => setTimeout(resolve, 3100));
218
-
219
- // Verify browser opened with correct URL
220
- expect(open).toHaveBeenCalledWith('http://localhost:5173');
221
- });
222
-
223
- it('should NOT open browser when open=false', async () => {
224
- await uiCommand({ port: 3001, open: false, dev: true });
225
-
226
- // Wait for startup delay (testing async behavior, not mocks)
227
- await new Promise(resolve => setTimeout(resolve, 3100));
228
-
229
- // Verify browser was not opened
230
- expect(open).not.toHaveBeenCalled();
231
- });
232
-
233
- it('should set PROJECT_ROOT environment variable', async () => {
234
- getCurrentRepositoryInfo.mockResolvedValue({
235
- path: '/custom/repo/path',
236
- name: 'custom-repo',
237
- currentSubPath: null
238
- });
239
-
240
- await uiCommand({ port: 3001, open: false, dev: true });
241
-
242
- expect(mockProcessManager.spawnProcess).toHaveBeenCalledWith(
243
- expect.any(String),
244
- expect.any(String),
245
- expect.any(Array),
246
- expect.objectContaining({
247
- env: expect.objectContaining({
248
- PROJECT_ROOT: '/custom/repo/path'
249
- })
250
- })
251
- );
252
- });
253
-
254
- it('should set REPOSITORY_INFO as JSON string with correct structure', async () => {
255
- await uiCommand({ port: 3001, open: false, dev: true });
256
-
257
- const call = mockProcessManager.spawnProcess.mock.calls[0];
258
- const env = call[3].env;
259
-
260
- // Verify REPOSITORY_INFO is valid JSON with correct structure
261
- expect(env.REPOSITORY_INFO).toBeDefined();
262
- const parsedInfo = JSON.parse(env.REPOSITORY_INFO);
263
-
264
- // Verify actual data matches mock
265
- expect(parsedInfo).toEqual({
266
- path: '/mock/frigg-repo',
267
- name: 'test-repo',
268
- currentSubPath: null
269
- });
270
- });
271
-
272
- it('should set AVAILABLE_REPOSITORIES with actual repository data', async () => {
273
- getCurrentRepositoryInfo.mockResolvedValue(null);
274
- discoverFriggRepositories.mockResolvedValue([
275
- { path: '/repos/frigg-1', name: 'frigg-1' }
276
- ]);
277
-
278
- await uiCommand({ port: 3001, open: false, dev: true });
279
-
280
- const call = mockProcessManager.spawnProcess.mock.calls[0];
281
- const env = call[3].env;
282
-
283
- // Verify AVAILABLE_REPOSITORIES is valid JSON with correct structure
284
- expect(env.AVAILABLE_REPOSITORIES).toBeDefined();
285
- const parsed = JSON.parse(env.AVAILABLE_REPOSITORIES);
286
-
287
- // Verify actual data matches mock
288
- expect(parsed).toEqual([
289
- { path: '/repos/frigg-1', name: 'frigg-1' }
290
- ]);
291
- });
292
- });
293
-
294
- describe('Error Handling', () => {
295
- it('should handle EADDRINUSE error', async () => {
296
- mockProcessManager.spawnProcess.mockImplementation(() => {
297
- const error = new Error('Port in use');
298
- error.code = 'EADDRINUSE';
299
- throw error;
300
- });
301
-
302
- await uiCommand({ port: 3001, open: false, dev: true });
303
-
304
- expect(consoleErrorSpy).toHaveBeenCalledWith(
305
- expect.stringContaining('Failed to start Management UI'),
306
- expect.any(String)
307
- );
308
- expect(consoleLogSpy).toHaveBeenCalledWith(
309
- expect.stringContaining('Port 3001 is already in use')
310
- );
311
- expect(processExitSpy).toHaveBeenCalledWith(1);
312
- });
313
-
314
- it('should handle generic errors', async () => {
315
- mockProcessManager.spawnProcess.mockImplementation(() => {
316
- throw new Error('Generic startup error');
317
- });
318
-
319
- await uiCommand({ port: 3001, open: false, dev: true });
320
-
321
- expect(consoleErrorSpy).toHaveBeenCalledWith(
322
- expect.stringContaining('Failed to start Management UI'),
323
- 'Generic startup error'
324
- );
325
- expect(processExitSpy).toHaveBeenCalledWith(1);
326
- });
327
- });
328
-
329
- describe('Process Management', () => {
330
- it('should create ProcessManager instance', async () => {
331
- await uiCommand({ port: 3001, open: false, dev: true });
332
-
333
- expect(ProcessManager).toHaveBeenCalled();
334
- });
335
-
336
- it('should keep process running with stdin.resume', async () => {
337
- await uiCommand({ port: 3001, open: false, dev: true });
338
-
339
- // Wait for startup delay (testing async behavior, not mocks)
340
- await new Promise(resolve => setTimeout(resolve, 2100));
341
-
342
- // Verify stdin.resume called to keep process alive
343
- expect(stdinResumeSpy).toHaveBeenCalled();
344
- });
345
- });
346
- });