@friggframework/devtools 2.0.0-next.41 → 2.0.0-next.42

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 (32) hide show
  1. package/frigg-cli/__tests__/unit/commands/build.test.js +173 -405
  2. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +548 -0
  3. package/frigg-cli/__tests__/unit/commands/install.test.js +359 -377
  4. package/frigg-cli/__tests__/unit/commands/ui.test.js +266 -512
  5. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +366 -0
  6. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +304 -0
  7. package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +486 -0
  8. package/frigg-cli/__tests__/utils/prisma-mock.js +194 -0
  9. package/frigg-cli/__tests__/utils/test-setup.js +22 -21
  10. package/frigg-cli/db-setup-command/index.js +186 -0
  11. package/frigg-cli/generate-command/__tests__/generate-command.test.js +151 -162
  12. package/frigg-cli/generate-iam-command.js +7 -4
  13. package/frigg-cli/index.js +9 -1
  14. package/frigg-cli/install-command/index.js +1 -1
  15. package/frigg-cli/jest.config.js +124 -0
  16. package/frigg-cli/package.json +4 -1
  17. package/frigg-cli/start-command/index.js +95 -2
  18. package/frigg-cli/start-command/start-command.test.js +161 -19
  19. package/frigg-cli/utils/database-validator.js +158 -0
  20. package/frigg-cli/utils/error-messages.js +257 -0
  21. package/frigg-cli/utils/prisma-runner.js +280 -0
  22. package/infrastructure/CLAUDE.md +481 -0
  23. package/infrastructure/IAM-POLICY-TEMPLATES.md +30 -12
  24. package/infrastructure/create-frigg-infrastructure.js +0 -2
  25. package/infrastructure/iam-generator.js +18 -38
  26. package/infrastructure/iam-generator.test.js +40 -8
  27. package/package.json +6 -6
  28. package/test/index.js +2 -4
  29. package/test/mock-integration.js +4 -14
  30. package/frigg-cli/__tests__/jest.config.js +0 -102
  31. package/frigg-cli/__tests__/utils/command-tester.js +0 -170
  32. package/test/auther-definition-tester.js +0 -125
@@ -0,0 +1,548 @@
1
+ // Mock all dependencies BEFORE importing dbSetupCommand
2
+ const mockValidator = {
3
+ validateDatabaseUrl: jest.fn(),
4
+ getDatabaseType: jest.fn(),
5
+ testDatabaseConnection: jest.fn(),
6
+ checkPrismaClientGenerated: jest.fn()
7
+ };
8
+
9
+ const mockRunner = {
10
+ runPrismaGenerate: jest.fn(),
11
+ checkDatabaseState: jest.fn(),
12
+ runPrismaMigrate: jest.fn(),
13
+ runPrismaDbPush: jest.fn(),
14
+ getMigrationCommand: jest.fn()
15
+ };
16
+
17
+ const mockErrorMessages = {
18
+ getDatabaseUrlMissingError: jest.fn(),
19
+ getDatabaseTypeNotConfiguredError: jest.fn(),
20
+ getDatabaseConnectionError: jest.fn(),
21
+ getPrismaCommandError: jest.fn(),
22
+ getDatabaseSetupSuccess: jest.fn()
23
+ };
24
+
25
+ jest.mock('../../../utils/database-validator', () => mockValidator);
26
+ jest.mock('../../../utils/prisma-runner', () => mockRunner);
27
+ jest.mock('../../../utils/error-messages', () => mockErrorMessages);
28
+ jest.mock('dotenv');
29
+
30
+ const { dbSetupCommand } = require('../../../db-setup-command');
31
+ const {
32
+ createMockDatabaseValidator,
33
+ createMockPrismaRunner
34
+ } = require('../../utils/prisma-mock');
35
+
36
+ const dotenv = require('dotenv');
37
+
38
+ describe('DB Setup Command', () => {
39
+ let mockConsoleLog;
40
+ let mockConsoleError;
41
+ let mockProcessExit;
42
+
43
+ beforeEach(() => {
44
+ // Set up default mock return values using the factory utilities
45
+ const defaultValidator = createMockDatabaseValidator();
46
+ const defaultRunner = createMockPrismaRunner();
47
+
48
+ // Apply default implementations
49
+ mockValidator.validateDatabaseUrl.mockImplementation(defaultValidator.validateDatabaseUrl);
50
+ mockValidator.getDatabaseType.mockImplementation(defaultValidator.getDatabaseType);
51
+ mockValidator.testDatabaseConnection.mockImplementation(defaultValidator.testDatabaseConnection);
52
+ mockValidator.checkPrismaClientGenerated.mockImplementation(defaultValidator.checkPrismaClientGenerated);
53
+
54
+ mockRunner.runPrismaGenerate.mockImplementation(defaultRunner.runPrismaGenerate);
55
+ mockRunner.checkDatabaseState.mockImplementation(defaultRunner.checkDatabaseState);
56
+ mockRunner.runPrismaMigrate.mockImplementation(defaultRunner.runPrismaMigrate);
57
+ mockRunner.runPrismaDbPush.mockImplementation(defaultRunner.runPrismaDbPush);
58
+ mockRunner.getMigrationCommand.mockImplementation(defaultRunner.getMigrationCommand);
59
+
60
+ // Mock dotenv
61
+ dotenv.config = jest.fn();
62
+
63
+ // Mock console and process.exit
64
+ mockConsoleLog = jest.spyOn(console, 'log').mockImplementation();
65
+ mockConsoleError = jest.spyOn(console, 'error').mockImplementation();
66
+ mockProcessExit = jest.spyOn(process, 'exit').mockImplementation();
67
+
68
+ // Mock error message functions with default return values
69
+ mockErrorMessages.getDatabaseUrlMissingError.mockReturnValue('DATABASE_URL missing error');
70
+ mockErrorMessages.getDatabaseTypeNotConfiguredError.mockReturnValue('DB type error');
71
+ mockErrorMessages.getDatabaseConnectionError.mockReturnValue('Connection error');
72
+ mockErrorMessages.getPrismaCommandError.mockReturnValue('Prisma error');
73
+ mockErrorMessages.getDatabaseSetupSuccess.mockReturnValue('Success message');
74
+ });
75
+
76
+ afterEach(() => {
77
+ mockConsoleLog.mockRestore();
78
+ mockConsoleError.mockRestore();
79
+ mockProcessExit.mockRestore();
80
+ jest.clearAllMocks();
81
+ });
82
+
83
+ describe('Success Cases', () => {
84
+ it('should complete setup successfully for MongoDB', async () => {
85
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'mongodb' });
86
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
87
+ generated: false // Client doesn't exist, will generate
88
+ });
89
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
90
+
91
+ await dbSetupCommand({ verbose: false, stage: 'development' });
92
+
93
+ expect(mockValidator.validateDatabaseUrl).toHaveBeenCalled();
94
+ expect(mockValidator.getDatabaseType).toHaveBeenCalled();
95
+ expect(mockValidator.checkPrismaClientGenerated).toHaveBeenCalledWith('mongodb');
96
+ expect(mockValidator.testDatabaseConnection).toHaveBeenCalled();
97
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', false);
98
+ expect(mockRunner.runPrismaDbPush).toHaveBeenCalled();
99
+ expect(mockProcessExit).not.toHaveBeenCalled();
100
+ });
101
+
102
+ it('should complete setup successfully for PostgreSQL', async () => {
103
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
104
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
105
+ generated: false // Client doesn't exist, will generate
106
+ });
107
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
108
+
109
+ await dbSetupCommand({ verbose: false, stage: 'development' });
110
+
111
+ expect(mockValidator.checkPrismaClientGenerated).toHaveBeenCalledWith('postgresql');
112
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('postgresql', false);
113
+ expect(mockRunner.runPrismaMigrate).toHaveBeenCalled();
114
+ expect(mockProcessExit).not.toHaveBeenCalled();
115
+ });
116
+
117
+ it('should skip migrations when already up-to-date (PostgreSQL)', async () => {
118
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
119
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: true });
120
+ mockRunner.getMigrationCommand.mockReturnValue('deploy');
121
+
122
+ await dbSetupCommand({ verbose: false, stage: 'production' });
123
+
124
+ expect(mockRunner.runPrismaMigrate).not.toHaveBeenCalled();
125
+ expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('already up-to-date'));
126
+ });
127
+
128
+ it('should use migrate dev in development stage', async () => {
129
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
130
+ mockRunner.getMigrationCommand.mockReturnValue('dev');
131
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
132
+
133
+ await dbSetupCommand({ verbose: false, stage: 'development' });
134
+
135
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('development');
136
+ expect(mockRunner.runPrismaMigrate).toHaveBeenCalledWith('dev', false);
137
+ });
138
+
139
+ it('should use migrate deploy in production stage', async () => {
140
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
141
+ mockRunner.getMigrationCommand.mockReturnValue('deploy');
142
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
143
+
144
+ await dbSetupCommand({ verbose: false, stage: 'production' });
145
+
146
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('production');
147
+ expect(mockRunner.runPrismaMigrate).toHaveBeenCalledWith('deploy', false);
148
+ });
149
+
150
+ it('should respect --verbose flag', async () => {
151
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
152
+ generated: false // Client doesn't exist, will generate
153
+ });
154
+
155
+ await dbSetupCommand({ verbose: true, stage: 'development' });
156
+
157
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', true);
158
+ });
159
+
160
+ it('should load .env file from project root', async () => {
161
+ await dbSetupCommand({ verbose: false, stage: 'development' });
162
+
163
+ expect(dotenv.config).toHaveBeenCalledWith(expect.objectContaining({
164
+ path: expect.stringContaining('.env')
165
+ }));
166
+ });
167
+ });
168
+
169
+ describe('Conditional Client Generation', () => {
170
+ it('should skip generation when client already exists', async () => {
171
+ // Client exists
172
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
173
+ generated: true,
174
+ path: '/path/to/client'
175
+ });
176
+
177
+ await dbSetupCommand({ verbose: false, stage: 'development' });
178
+
179
+ // Should check if client exists
180
+ expect(mockValidator.checkPrismaClientGenerated).toHaveBeenCalledWith('mongodb');
181
+ // Should NOT call generate
182
+ expect(mockRunner.runPrismaGenerate).not.toHaveBeenCalled();
183
+ // Should still test connection and complete setup
184
+ expect(mockValidator.testDatabaseConnection).toHaveBeenCalled();
185
+ expect(mockProcessExit).not.toHaveBeenCalled();
186
+ });
187
+
188
+ it('should generate client when it does not exist', async () => {
189
+ // Client does NOT exist
190
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
191
+ generated: false,
192
+ error: 'Client not found'
193
+ });
194
+
195
+ await dbSetupCommand({ verbose: false, stage: 'development' });
196
+
197
+ // Should check if client exists
198
+ expect(mockValidator.checkPrismaClientGenerated).toHaveBeenCalledWith('mongodb');
199
+ // Should call generate
200
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', false);
201
+ // Should complete setup
202
+ expect(mockProcessExit).not.toHaveBeenCalled();
203
+ });
204
+
205
+ it('should regenerate client when --force flag is provided', async () => {
206
+ // Client exists
207
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
208
+ generated: true,
209
+ path: '/path/to/client'
210
+ });
211
+
212
+ await dbSetupCommand({ verbose: false, stage: 'development', force: true });
213
+
214
+ // Should check if client exists
215
+ expect(mockValidator.checkPrismaClientGenerated).toHaveBeenCalledWith('mongodb');
216
+ // Should STILL call generate because of --force
217
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', false);
218
+ // Should complete setup
219
+ expect(mockProcessExit).not.toHaveBeenCalled();
220
+ });
221
+
222
+ it('should show client location in verbose mode when skipping generation', async () => {
223
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
224
+ generated: true,
225
+ path: '/path/to/prisma/client'
226
+ });
227
+
228
+ await dbSetupCommand({ verbose: true, stage: 'development' });
229
+
230
+ // Should log the client path
231
+ expect(mockConsoleLog).toHaveBeenCalledWith(
232
+ expect.stringContaining('/path/to/prisma/client')
233
+ );
234
+ expect(mockRunner.runPrismaGenerate).not.toHaveBeenCalled();
235
+ });
236
+
237
+ it('should generate for different database types', async () => {
238
+ // Test PostgreSQL
239
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
240
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
241
+ generated: false
242
+ });
243
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
244
+
245
+ await dbSetupCommand({ verbose: false, stage: 'development' });
246
+
247
+ expect(mockValidator.checkPrismaClientGenerated).toHaveBeenCalledWith('postgresql');
248
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('postgresql', false);
249
+ });
250
+ });
251
+
252
+ describe('Failure Cases - Validation', () => {
253
+ it('should fail when DATABASE_URL missing', async () => {
254
+ mockValidator.validateDatabaseUrl.mockReturnValue({
255
+ valid: false,
256
+ error: 'DATABASE_URL not found'
257
+ });
258
+
259
+ await dbSetupCommand({});
260
+
261
+ expect(mockConsoleError).toHaveBeenCalled();
262
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
263
+ });
264
+
265
+ it('should fail when DATABASE_URL is empty', async () => {
266
+ mockValidator.validateDatabaseUrl.mockReturnValue({
267
+ valid: false,
268
+ error: 'DATABASE_URL is empty'
269
+ });
270
+
271
+ await dbSetupCommand({});
272
+
273
+ expect(mockErrorMessages.getDatabaseUrlMissingError).toHaveBeenCalled();
274
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
275
+ });
276
+
277
+ it('should fail when database type not configured', async () => {
278
+ mockValidator.getDatabaseType.mockReturnValue({
279
+ error: 'Database not configured'
280
+ });
281
+
282
+ await dbSetupCommand({});
283
+
284
+ expect(mockErrorMessages.getDatabaseTypeNotConfiguredError).toHaveBeenCalled();
285
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
286
+ });
287
+
288
+ it('should fail when backend definition not found', async () => {
289
+ mockValidator.getDatabaseType.mockReturnValue({
290
+ error: 'Backend not found'
291
+ });
292
+
293
+ await dbSetupCommand({});
294
+
295
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
296
+ });
297
+ });
298
+
299
+ describe('Failure Cases - Connection', () => {
300
+ it('should fail when database connection times out', async () => {
301
+ mockValidator.testDatabaseConnection.mockResolvedValue({
302
+ connected: false,
303
+ error: 'Connection timeout'
304
+ });
305
+
306
+ await dbSetupCommand({});
307
+
308
+ expect(mockErrorMessages.getDatabaseConnectionError).toHaveBeenCalledWith(
309
+ 'Connection timeout',
310
+ 'mongodb'
311
+ );
312
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
313
+ });
314
+
315
+ it('should fail when database credentials invalid', async () => {
316
+ mockValidator.testDatabaseConnection.mockResolvedValue({
317
+ connected: false,
318
+ error: 'Authentication failed'
319
+ });
320
+
321
+ await dbSetupCommand({});
322
+
323
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
324
+ });
325
+
326
+ it('should fail when database not accessible', async () => {
327
+ mockValidator.testDatabaseConnection.mockResolvedValue({
328
+ connected: false,
329
+ error: 'Connection refused'
330
+ });
331
+
332
+ await dbSetupCommand({});
333
+
334
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
335
+ });
336
+ });
337
+
338
+ describe('Failure Cases - Prisma Operations', () => {
339
+ it('should fail when prisma generate fails', async () => {
340
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
341
+ generated: false // Client doesn't exist, will attempt generation
342
+ });
343
+ mockRunner.runPrismaGenerate.mockResolvedValue({
344
+ success: false,
345
+ error: 'Generation failed'
346
+ });
347
+
348
+ await dbSetupCommand({});
349
+
350
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalledWith(
351
+ 'generate',
352
+ 'Generation failed'
353
+ );
354
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
355
+ });
356
+
357
+ it('should fail when migrate dev fails (PostgreSQL)', async () => {
358
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
359
+ mockRunner.getMigrationCommand.mockReturnValue('dev');
360
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
361
+ mockRunner.runPrismaMigrate.mockResolvedValue({
362
+ success: false,
363
+ error: 'Migration failed'
364
+ });
365
+
366
+ await dbSetupCommand({ stage: 'development' });
367
+
368
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalledWith(
369
+ 'migrate',
370
+ 'Migration failed'
371
+ );
372
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
373
+ });
374
+
375
+ it('should fail when migrate deploy fails (PostgreSQL)', async () => {
376
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
377
+ mockRunner.getMigrationCommand.mockReturnValue('deploy');
378
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
379
+ mockRunner.runPrismaMigrate.mockResolvedValue({
380
+ success: false,
381
+ error: 'Deploy failed'
382
+ });
383
+
384
+ await dbSetupCommand({ stage: 'production' });
385
+
386
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
387
+ });
388
+
389
+ it('should fail when db push fails (MongoDB)', async () => {
390
+ mockRunner.runPrismaDbPush.mockResolvedValue({
391
+ success: false,
392
+ error: 'Push failed'
393
+ });
394
+
395
+ await dbSetupCommand({});
396
+
397
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalledWith(
398
+ 'db push',
399
+ 'Push failed'
400
+ );
401
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
402
+ });
403
+
404
+ it('should fail when schema file missing', async () => {
405
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
406
+ generated: false // Client doesn't exist, will attempt generation
407
+ });
408
+ mockRunner.runPrismaGenerate.mockResolvedValue({
409
+ success: false,
410
+ error: 'Schema not found'
411
+ });
412
+
413
+ await dbSetupCommand({});
414
+
415
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
416
+ });
417
+ });
418
+
419
+ describe('Error Message Validation', () => {
420
+ it('should display helpful error for missing DATABASE_URL', async () => {
421
+ mockValidator.validateDatabaseUrl.mockReturnValue({
422
+ valid: false,
423
+ error: 'Not found'
424
+ });
425
+
426
+ await dbSetupCommand({});
427
+
428
+ expect(mockErrorMessages.getDatabaseUrlMissingError).toHaveBeenCalled();
429
+ });
430
+
431
+ it('should display helpful error for connection failure', async () => {
432
+ mockValidator.testDatabaseConnection.mockResolvedValue({
433
+ connected: false,
434
+ error: 'Network error'
435
+ });
436
+
437
+ await dbSetupCommand({});
438
+
439
+ expect(mockErrorMessages.getDatabaseConnectionError).toHaveBeenCalledWith(
440
+ 'Network error',
441
+ expect.any(String)
442
+ );
443
+ });
444
+
445
+ it('should display helpful error for Prisma failures', async () => {
446
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
447
+ generated: false // Client doesn't exist, will attempt generation
448
+ });
449
+ mockRunner.runPrismaGenerate.mockResolvedValue({
450
+ success: false,
451
+ error: 'Some error',
452
+ output: 'Detailed output'
453
+ });
454
+
455
+ await dbSetupCommand({});
456
+
457
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalled();
458
+ });
459
+
460
+ it('should exit with code 1 on failure', async () => {
461
+ mockValidator.validateDatabaseUrl.mockReturnValue({
462
+ valid: false
463
+ });
464
+
465
+ await dbSetupCommand({});
466
+
467
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
468
+ });
469
+
470
+ it('should not exit with code 0 on failure', async () => {
471
+ mockValidator.validateDatabaseUrl.mockReturnValue({
472
+ valid: false
473
+ });
474
+
475
+ await dbSetupCommand({});
476
+
477
+ expect(mockProcessExit).not.toHaveBeenCalledWith(0);
478
+ });
479
+
480
+ it('should display success message on completion', async () => {
481
+ await dbSetupCommand({ stage: 'development' });
482
+
483
+ expect(mockErrorMessages.getDatabaseSetupSuccess).toHaveBeenCalledWith(
484
+ 'mongodb',
485
+ 'development'
486
+ );
487
+ });
488
+ });
489
+
490
+ describe('Verbose Output', () => {
491
+ it('should show verbose output when flag enabled', async () => {
492
+ await dbSetupCommand({ verbose: true });
493
+
494
+ // Verbose calls should show console output
495
+ expect(mockConsoleLog).toHaveBeenCalled();
496
+ });
497
+
498
+ it('should pass verbose flag to Prisma commands', async () => {
499
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
500
+ generated: false // Client doesn't exist, will generate
501
+ });
502
+
503
+ await dbSetupCommand({ verbose: true });
504
+
505
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', true);
506
+ expect(mockRunner.runPrismaDbPush).toHaveBeenCalledWith(true);
507
+ });
508
+
509
+ it('should not show verbose output when flag disabled', async () => {
510
+ mockValidator.checkPrismaClientGenerated.mockReturnValue({
511
+ generated: false // Client doesn't exist, will generate
512
+ });
513
+
514
+ await dbSetupCommand({ verbose: false });
515
+
516
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', false);
517
+ });
518
+ });
519
+
520
+ describe('Stage Handling', () => {
521
+ it('should use provided stage option', async () => {
522
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
523
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
524
+
525
+ await dbSetupCommand({ stage: 'production' });
526
+
527
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('production');
528
+ });
529
+
530
+ it('should default to development when no stage provided', async () => {
531
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
532
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
533
+
534
+ await dbSetupCommand({});
535
+
536
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalled();
537
+ });
538
+
539
+ it('should handle different stage values', async () => {
540
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
541
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
542
+
543
+ await dbSetupCommand({ stage: 'staging' });
544
+
545
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('staging');
546
+ });
547
+ });
548
+ });