@friggframework/devtools 2.0.0--canary.395.f03dc2b.0 → 2.0.0--canary.395.495dc7d.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.
@@ -57,6 +57,30 @@ module.exports = {
57
57
  functions: 90,
58
58
  lines: 90,
59
59
  statements: 90
60
+ },
61
+ '../db-setup-command/index.js': {
62
+ branches: 90,
63
+ functions: 90,
64
+ lines: 90,
65
+ statements: 90
66
+ },
67
+ '../utils/database-validator.js': {
68
+ branches: 85,
69
+ functions: 85,
70
+ lines: 85,
71
+ statements: 85
72
+ },
73
+ '../utils/prisma-runner.js': {
74
+ branches: 85,
75
+ functions: 85,
76
+ lines: 85,
77
+ statements: 85
78
+ },
79
+ '../utils/error-messages.js': {
80
+ branches: 85,
81
+ functions: 85,
82
+ lines: 85,
83
+ statements: 85
60
84
  }
61
85
  },
62
86
  setupFilesAfterEnv: [
@@ -0,0 +1,436 @@
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
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
87
+
88
+ await dbSetupCommand({ verbose: false, stage: 'development' });
89
+
90
+ expect(mockValidator.validateDatabaseUrl).toHaveBeenCalled();
91
+ expect(mockValidator.getDatabaseType).toHaveBeenCalled();
92
+ expect(mockValidator.testDatabaseConnection).toHaveBeenCalled();
93
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', false);
94
+ expect(mockRunner.runPrismaDbPush).toHaveBeenCalled();
95
+ expect(mockProcessExit).not.toHaveBeenCalled();
96
+ });
97
+
98
+ it('should complete setup successfully for PostgreSQL', async () => {
99
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
100
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
101
+
102
+ await dbSetupCommand({ verbose: false, stage: 'development' });
103
+
104
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('postgresql', false);
105
+ expect(mockRunner.runPrismaMigrate).toHaveBeenCalled();
106
+ expect(mockProcessExit).not.toHaveBeenCalled();
107
+ });
108
+
109
+ it('should skip migrations when already up-to-date (PostgreSQL)', async () => {
110
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
111
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: true });
112
+ mockRunner.getMigrationCommand.mockReturnValue('deploy');
113
+
114
+ await dbSetupCommand({ verbose: false, stage: 'production' });
115
+
116
+ expect(mockRunner.runPrismaMigrate).not.toHaveBeenCalled();
117
+ expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('already up-to-date'));
118
+ });
119
+
120
+ it('should use migrate dev in development stage', async () => {
121
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
122
+ mockRunner.getMigrationCommand.mockReturnValue('dev');
123
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
124
+
125
+ await dbSetupCommand({ verbose: false, stage: 'development' });
126
+
127
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('development');
128
+ expect(mockRunner.runPrismaMigrate).toHaveBeenCalledWith('dev', false);
129
+ });
130
+
131
+ it('should use migrate deploy in production stage', async () => {
132
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
133
+ mockRunner.getMigrationCommand.mockReturnValue('deploy');
134
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
135
+
136
+ await dbSetupCommand({ verbose: false, stage: 'production' });
137
+
138
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('production');
139
+ expect(mockRunner.runPrismaMigrate).toHaveBeenCalledWith('deploy', false);
140
+ });
141
+
142
+ it('should respect --verbose flag', async () => {
143
+ await dbSetupCommand({ verbose: true, stage: 'development' });
144
+
145
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', true);
146
+ });
147
+
148
+ it('should load .env file from project root', async () => {
149
+ await dbSetupCommand({ verbose: false, stage: 'development' });
150
+
151
+ expect(dotenv.config).toHaveBeenCalledWith(expect.objectContaining({
152
+ path: expect.stringContaining('.env')
153
+ }));
154
+ });
155
+ });
156
+
157
+ describe('Failure Cases - Validation', () => {
158
+ it('should fail when DATABASE_URL missing', async () => {
159
+ mockValidator.validateDatabaseUrl.mockReturnValue({
160
+ valid: false,
161
+ error: 'DATABASE_URL not found'
162
+ });
163
+
164
+ await dbSetupCommand({});
165
+
166
+ expect(mockConsoleError).toHaveBeenCalled();
167
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
168
+ });
169
+
170
+ it('should fail when DATABASE_URL is empty', async () => {
171
+ mockValidator.validateDatabaseUrl.mockReturnValue({
172
+ valid: false,
173
+ error: 'DATABASE_URL is empty'
174
+ });
175
+
176
+ await dbSetupCommand({});
177
+
178
+ expect(mockErrorMessages.getDatabaseUrlMissingError).toHaveBeenCalled();
179
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
180
+ });
181
+
182
+ it('should fail when database type not configured', async () => {
183
+ mockValidator.getDatabaseType.mockReturnValue({
184
+ error: 'Database not configured'
185
+ });
186
+
187
+ await dbSetupCommand({});
188
+
189
+ expect(mockErrorMessages.getDatabaseTypeNotConfiguredError).toHaveBeenCalled();
190
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
191
+ });
192
+
193
+ it('should fail when backend definition not found', async () => {
194
+ mockValidator.getDatabaseType.mockReturnValue({
195
+ error: 'Backend not found'
196
+ });
197
+
198
+ await dbSetupCommand({});
199
+
200
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
201
+ });
202
+ });
203
+
204
+ describe('Failure Cases - Connection', () => {
205
+ it('should fail when database connection times out', async () => {
206
+ mockValidator.testDatabaseConnection.mockResolvedValue({
207
+ connected: false,
208
+ error: 'Connection timeout'
209
+ });
210
+
211
+ await dbSetupCommand({});
212
+
213
+ expect(mockErrorMessages.getDatabaseConnectionError).toHaveBeenCalledWith(
214
+ 'Connection timeout',
215
+ 'mongodb'
216
+ );
217
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
218
+ });
219
+
220
+ it('should fail when database credentials invalid', async () => {
221
+ mockValidator.testDatabaseConnection.mockResolvedValue({
222
+ connected: false,
223
+ error: 'Authentication failed'
224
+ });
225
+
226
+ await dbSetupCommand({});
227
+
228
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
229
+ });
230
+
231
+ it('should fail when database not accessible', async () => {
232
+ mockValidator.testDatabaseConnection.mockResolvedValue({
233
+ connected: false,
234
+ error: 'Connection refused'
235
+ });
236
+
237
+ await dbSetupCommand({});
238
+
239
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
240
+ });
241
+ });
242
+
243
+ describe('Failure Cases - Prisma Operations', () => {
244
+ it('should fail when prisma generate fails', async () => {
245
+ mockRunner.runPrismaGenerate.mockResolvedValue({
246
+ success: false,
247
+ error: 'Generation failed'
248
+ });
249
+
250
+ await dbSetupCommand({});
251
+
252
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalledWith(
253
+ 'generate',
254
+ 'Generation failed'
255
+ );
256
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
257
+ });
258
+
259
+ it('should fail when migrate dev fails (PostgreSQL)', async () => {
260
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
261
+ mockRunner.getMigrationCommand.mockReturnValue('dev');
262
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
263
+ mockRunner.runPrismaMigrate.mockResolvedValue({
264
+ success: false,
265
+ error: 'Migration failed'
266
+ });
267
+
268
+ await dbSetupCommand({ stage: 'development' });
269
+
270
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalledWith(
271
+ 'migrate',
272
+ 'Migration failed'
273
+ );
274
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
275
+ });
276
+
277
+ it('should fail when migrate deploy fails (PostgreSQL)', async () => {
278
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
279
+ mockRunner.getMigrationCommand.mockReturnValue('deploy');
280
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
281
+ mockRunner.runPrismaMigrate.mockResolvedValue({
282
+ success: false,
283
+ error: 'Deploy failed'
284
+ });
285
+
286
+ await dbSetupCommand({ stage: 'production' });
287
+
288
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
289
+ });
290
+
291
+ it('should fail when db push fails (MongoDB)', async () => {
292
+ mockRunner.runPrismaDbPush.mockResolvedValue({
293
+ success: false,
294
+ error: 'Push failed'
295
+ });
296
+
297
+ await dbSetupCommand({});
298
+
299
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalledWith(
300
+ 'db push',
301
+ 'Push failed'
302
+ );
303
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
304
+ });
305
+
306
+ it('should fail when schema file missing', async () => {
307
+ mockRunner.runPrismaGenerate.mockResolvedValue({
308
+ success: false,
309
+ error: 'Schema not found'
310
+ });
311
+
312
+ await dbSetupCommand({});
313
+
314
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
315
+ });
316
+ });
317
+
318
+ describe('Error Message Validation', () => {
319
+ it('should display helpful error for missing DATABASE_URL', async () => {
320
+ mockValidator.validateDatabaseUrl.mockReturnValue({
321
+ valid: false,
322
+ error: 'Not found'
323
+ });
324
+
325
+ await dbSetupCommand({});
326
+
327
+ expect(mockErrorMessages.getDatabaseUrlMissingError).toHaveBeenCalled();
328
+ });
329
+
330
+ it('should display helpful error for connection failure', async () => {
331
+ mockValidator.testDatabaseConnection.mockResolvedValue({
332
+ connected: false,
333
+ error: 'Network error'
334
+ });
335
+
336
+ await dbSetupCommand({});
337
+
338
+ expect(mockErrorMessages.getDatabaseConnectionError).toHaveBeenCalledWith(
339
+ 'Network error',
340
+ expect.any(String)
341
+ );
342
+ });
343
+
344
+ it('should display helpful error for Prisma failures', async () => {
345
+ mockRunner.runPrismaGenerate.mockResolvedValue({
346
+ success: false,
347
+ error: 'Some error',
348
+ output: 'Detailed output'
349
+ });
350
+
351
+ await dbSetupCommand({});
352
+
353
+ expect(mockErrorMessages.getPrismaCommandError).toHaveBeenCalled();
354
+ });
355
+
356
+ it('should exit with code 1 on failure', async () => {
357
+ mockValidator.validateDatabaseUrl.mockReturnValue({
358
+ valid: false
359
+ });
360
+
361
+ await dbSetupCommand({});
362
+
363
+ expect(mockProcessExit).toHaveBeenCalledWith(1);
364
+ });
365
+
366
+ it('should not exit with code 0 on failure', async () => {
367
+ mockValidator.validateDatabaseUrl.mockReturnValue({
368
+ valid: false
369
+ });
370
+
371
+ await dbSetupCommand({});
372
+
373
+ expect(mockProcessExit).not.toHaveBeenCalledWith(0);
374
+ });
375
+
376
+ it('should display success message on completion', async () => {
377
+ await dbSetupCommand({ stage: 'development' });
378
+
379
+ expect(mockErrorMessages.getDatabaseSetupSuccess).toHaveBeenCalledWith(
380
+ 'mongodb',
381
+ 'development'
382
+ );
383
+ });
384
+ });
385
+
386
+ describe('Verbose Output', () => {
387
+ it('should show verbose output when flag enabled', async () => {
388
+ await dbSetupCommand({ verbose: true });
389
+
390
+ // Verbose calls should show console output
391
+ expect(mockConsoleLog).toHaveBeenCalled();
392
+ });
393
+
394
+ it('should pass verbose flag to Prisma commands', async () => {
395
+ await dbSetupCommand({ verbose: true });
396
+
397
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', true);
398
+ expect(mockRunner.runPrismaDbPush).toHaveBeenCalledWith(true);
399
+ });
400
+
401
+ it('should not show verbose output when flag disabled', async () => {
402
+ await dbSetupCommand({ verbose: false });
403
+
404
+ expect(mockRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', false);
405
+ });
406
+ });
407
+
408
+ describe('Stage Handling', () => {
409
+ it('should use provided stage option', async () => {
410
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
411
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
412
+
413
+ await dbSetupCommand({ stage: 'production' });
414
+
415
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('production');
416
+ });
417
+
418
+ it('should default to development when no stage provided', async () => {
419
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
420
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
421
+
422
+ await dbSetupCommand({});
423
+
424
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalled();
425
+ });
426
+
427
+ it('should handle different stage values', async () => {
428
+ mockValidator.getDatabaseType.mockReturnValue({ dbType: 'postgresql' });
429
+ mockRunner.checkDatabaseState.mockResolvedValue({ upToDate: false });
430
+
431
+ await dbSetupCommand({ stage: 'staging' });
432
+
433
+ expect(mockRunner.getMigrationCommand).toHaveBeenCalledWith('staging');
434
+ });
435
+ });
436
+ });