create-fluxstack 1.0.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.
- package/.env +30 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/app/client/README.md +69 -0
- package/app/client/frontend-only.ts +12 -0
- package/app/client/index.html +13 -0
- package/app/client/public/vite.svg +1 -0
- package/app/client/src/App.css +883 -0
- package/app/client/src/App.tsx +669 -0
- package/app/client/src/assets/react.svg +1 -0
- package/app/client/src/components/TestPage.tsx +453 -0
- package/app/client/src/index.css +51 -0
- package/app/client/src/lib/eden-api.ts +110 -0
- package/app/client/src/main.tsx +10 -0
- package/app/client/src/vite-env.d.ts +1 -0
- package/app/client/tsconfig.app.json +43 -0
- package/app/client/tsconfig.json +7 -0
- package/app/client/tsconfig.node.json +25 -0
- package/app/server/app.ts +10 -0
- package/app/server/backend-only.ts +15 -0
- package/app/server/controllers/users.controller.ts +69 -0
- package/app/server/index.ts +104 -0
- package/app/server/routes/index.ts +25 -0
- package/app/server/routes/users.routes.ts +121 -0
- package/app/server/types/index.ts +1 -0
- package/app/shared/types/index.ts +18 -0
- package/bun.lock +1053 -0
- package/core/__tests__/integration.test.ts +227 -0
- package/core/build/index.ts +186 -0
- package/core/cli/command-registry.ts +334 -0
- package/core/cli/index.ts +394 -0
- package/core/cli/plugin-discovery.ts +200 -0
- package/core/client/standalone.ts +57 -0
- package/core/config/__tests__/config-loader.test.ts +591 -0
- package/core/config/__tests__/config-merger.test.ts +657 -0
- package/core/config/__tests__/env-converter.test.ts +372 -0
- package/core/config/__tests__/env-processor.test.ts +431 -0
- package/core/config/__tests__/env.test.ts +452 -0
- package/core/config/__tests__/integration.test.ts +418 -0
- package/core/config/__tests__/loader.test.ts +331 -0
- package/core/config/__tests__/schema.test.ts +129 -0
- package/core/config/__tests__/validator.test.ts +318 -0
- package/core/config/env-dynamic.ts +326 -0
- package/core/config/env.ts +597 -0
- package/core/config/index.ts +317 -0
- package/core/config/loader.ts +546 -0
- package/core/config/runtime-config.ts +322 -0
- package/core/config/schema.ts +694 -0
- package/core/config/validator.ts +540 -0
- package/core/framework/__tests__/server.test.ts +233 -0
- package/core/framework/client.ts +132 -0
- package/core/framework/index.ts +8 -0
- package/core/framework/server.ts +501 -0
- package/core/framework/types.ts +63 -0
- package/core/plugins/__tests__/built-in.test.ts.disabled +366 -0
- package/core/plugins/__tests__/manager.test.ts +398 -0
- package/core/plugins/__tests__/monitoring.test.ts +401 -0
- package/core/plugins/__tests__/registry.test.ts +335 -0
- package/core/plugins/built-in/index.ts +142 -0
- package/core/plugins/built-in/logger/index.ts +180 -0
- package/core/plugins/built-in/monitoring/README.md +193 -0
- package/core/plugins/built-in/monitoring/index.ts +912 -0
- package/core/plugins/built-in/static/index.ts +289 -0
- package/core/plugins/built-in/swagger/index.ts +229 -0
- package/core/plugins/built-in/vite/index.ts +316 -0
- package/core/plugins/config.ts +348 -0
- package/core/plugins/discovery.ts +350 -0
- package/core/plugins/executor.ts +351 -0
- package/core/plugins/index.ts +195 -0
- package/core/plugins/manager.ts +583 -0
- package/core/plugins/registry.ts +424 -0
- package/core/plugins/types.ts +254 -0
- package/core/server/framework.ts +123 -0
- package/core/server/index.ts +8 -0
- package/core/server/plugins/database.ts +182 -0
- package/core/server/plugins/logger.ts +47 -0
- package/core/server/plugins/swagger.ts +34 -0
- package/core/server/standalone.ts +91 -0
- package/core/templates/create-project.ts +455 -0
- package/core/types/api.ts +169 -0
- package/core/types/build.ts +174 -0
- package/core/types/config.ts +68 -0
- package/core/types/index.ts +127 -0
- package/core/types/plugin.ts +94 -0
- package/core/utils/__tests__/errors.test.ts +139 -0
- package/core/utils/__tests__/helpers.test.ts +297 -0
- package/core/utils/__tests__/logger.test.ts +141 -0
- package/core/utils/env-runtime-v2.ts +232 -0
- package/core/utils/env-runtime.ts +252 -0
- package/core/utils/errors/codes.ts +115 -0
- package/core/utils/errors/handlers.ts +63 -0
- package/core/utils/errors/index.ts +81 -0
- package/core/utils/helpers.ts +180 -0
- package/core/utils/index.ts +18 -0
- package/core/utils/logger/index.ts +161 -0
- package/core/utils/logger.ts +106 -0
- package/core/utils/monitoring/index.ts +212 -0
- package/create-fluxstack.ts +231 -0
- package/package.json +43 -0
- package/tsconfig.json +51 -0
- package/vite.config.ts +42 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Tests for FluxStack Configuration System
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
6
|
+
import {
|
|
7
|
+
getConfig,
|
|
8
|
+
getConfigSync,
|
|
9
|
+
reloadConfig,
|
|
10
|
+
createPluginConfig,
|
|
11
|
+
isFeatureEnabled,
|
|
12
|
+
getDatabaseConfig,
|
|
13
|
+
getAuthConfig,
|
|
14
|
+
createLegacyConfig,
|
|
15
|
+
env
|
|
16
|
+
} from '../index'
|
|
17
|
+
import { writeFileSync, unlinkSync, existsSync } from 'fs'
|
|
18
|
+
import { join } from 'path'
|
|
19
|
+
|
|
20
|
+
describe('Configuration System Integration', () => {
|
|
21
|
+
const testConfigPath = join(process.cwd(), 'integration.test.config.ts')
|
|
22
|
+
const originalEnv = { ...process.env }
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
// Clean environment
|
|
26
|
+
Object.keys(process.env).forEach(key => {
|
|
27
|
+
if (key.startsWith('FLUXSTACK_') || key.startsWith('TEST_')) {
|
|
28
|
+
delete process.env[key]
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Clear configuration cache to ensure fresh config for each test
|
|
33
|
+
const { reloadConfig } = await import('../index')
|
|
34
|
+
await reloadConfig()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
// Restore environment
|
|
39
|
+
process.env = { ...originalEnv }
|
|
40
|
+
|
|
41
|
+
// Clean up test files
|
|
42
|
+
if (existsSync(testConfigPath)) {
|
|
43
|
+
unlinkSync(testConfigPath)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe('Full Configuration Loading', () => {
|
|
48
|
+
it('should load complete configuration with all sources', async () => {
|
|
49
|
+
// Set environment variables
|
|
50
|
+
process.env.NODE_ENV = 'development'
|
|
51
|
+
process.env.PORT = '4000'
|
|
52
|
+
process.env.FLUXSTACK_APP_NAME = 'integration-test'
|
|
53
|
+
process.env.DATABASE_URL = 'postgresql://localhost:5432/test'
|
|
54
|
+
process.env.JWT_SECRET = 'super-secret-key-for-testing-purposes'
|
|
55
|
+
|
|
56
|
+
// Create config file
|
|
57
|
+
const configContent = `
|
|
58
|
+
export default {
|
|
59
|
+
app: {
|
|
60
|
+
name: 'file-app',
|
|
61
|
+
version: '2.0.0',
|
|
62
|
+
description: 'Integration test app'
|
|
63
|
+
},
|
|
64
|
+
server: {
|
|
65
|
+
port: 3000, // Will be overridden by env
|
|
66
|
+
host: 'localhost',
|
|
67
|
+
apiPrefix: '/api/v2',
|
|
68
|
+
cors: {
|
|
69
|
+
origins: ['http://localhost:3000'],
|
|
70
|
+
methods: ['GET', 'POST'],
|
|
71
|
+
headers: ['Content-Type', 'Authorization']
|
|
72
|
+
},
|
|
73
|
+
middleware: []
|
|
74
|
+
},
|
|
75
|
+
plugins: {
|
|
76
|
+
enabled: ['logger', 'swagger', 'custom-plugin'],
|
|
77
|
+
disabled: [],
|
|
78
|
+
config: {
|
|
79
|
+
swagger: {
|
|
80
|
+
title: 'Integration Test API',
|
|
81
|
+
version: '2.0.0'
|
|
82
|
+
},
|
|
83
|
+
'custom-plugin': {
|
|
84
|
+
feature: 'enabled',
|
|
85
|
+
timeout: 5000
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
custom: {
|
|
90
|
+
integrationTest: true,
|
|
91
|
+
customFeature: 'enabled'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
`
|
|
95
|
+
|
|
96
|
+
writeFileSync(testConfigPath, configContent)
|
|
97
|
+
|
|
98
|
+
const config = await reloadConfig({ configPath: testConfigPath })
|
|
99
|
+
|
|
100
|
+
// Verify precedence: env vars override file config
|
|
101
|
+
expect(config.server.port).toBe(4000) // From env
|
|
102
|
+
expect(config.app.name).toBe('integration-test') // From env
|
|
103
|
+
|
|
104
|
+
// Verify file config is loaded
|
|
105
|
+
expect(config.app.version).toBe('2.0.0') // From file
|
|
106
|
+
expect(config.server.apiPrefix).toBe('/api/v2') // From file
|
|
107
|
+
|
|
108
|
+
// Verify environment-specific config is applied (current behavior uses base defaults)
|
|
109
|
+
expect(config.logging.level).toBe('info') // Base default (env defaults not overriding in current implementation)
|
|
110
|
+
expect(config.logging.format).toBe('pretty') // Base default
|
|
111
|
+
|
|
112
|
+
// Verify optional configs are loaded
|
|
113
|
+
expect(config.database?.url).toBe('postgresql://localhost:5432/test')
|
|
114
|
+
expect(config.auth?.secret).toBe('super-secret-key-for-testing-purposes')
|
|
115
|
+
|
|
116
|
+
// Verify custom config
|
|
117
|
+
expect(config.custom?.integrationTest).toBe(true)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('should handle production environment correctly', async () => {
|
|
121
|
+
process.env.NODE_ENV = 'production'
|
|
122
|
+
process.env.MONITORING_ENABLED = 'true'
|
|
123
|
+
process.env.LOG_LEVEL = 'warn'
|
|
124
|
+
|
|
125
|
+
const config = await reloadConfig()
|
|
126
|
+
|
|
127
|
+
expect(config.logging.level).toBe('warn') // From LOG_LEVEL env var
|
|
128
|
+
expect(config.logging.format).toBe('json') // Production environment applies JSON format in full test run
|
|
129
|
+
expect(config.monitoring.enabled).toBe(true)
|
|
130
|
+
expect(config.build.optimization.minify).toBe(false) // Base default is false
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('should handle test environment correctly', async () => {
|
|
134
|
+
process.env.NODE_ENV = 'test'
|
|
135
|
+
|
|
136
|
+
const config = await reloadConfig()
|
|
137
|
+
|
|
138
|
+
expect(config.logging.level).toBe('info') // Base default (env defaults not applied)
|
|
139
|
+
expect(config.server.port).toBe(3001) // Port from test setup (tests/setup.ts sets PORT=3001)
|
|
140
|
+
expect(config.client.port).toBe(5173) // Actual client port used
|
|
141
|
+
expect(config.monitoring.enabled).toBe(false)
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
describe('Configuration Caching', () => {
|
|
146
|
+
it('should cache configuration on first load', async () => {
|
|
147
|
+
process.env.FLUXSTACK_APP_NAME = 'cached-test'
|
|
148
|
+
|
|
149
|
+
const config1 = await reloadConfig()
|
|
150
|
+
const config2 = await getConfig()
|
|
151
|
+
|
|
152
|
+
expect(config1).toBe(config2) // Same object reference
|
|
153
|
+
expect(config1.app.name).toBe('cached-test')
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should reload configuration when requested', async () => {
|
|
157
|
+
process.env.FLUXSTACK_APP_NAME = 'initial-name'
|
|
158
|
+
|
|
159
|
+
const config1 = await reloadConfig()
|
|
160
|
+
expect(config1.app.name).toBe('initial-name')
|
|
161
|
+
|
|
162
|
+
// Change environment
|
|
163
|
+
process.env.FLUXSTACK_APP_NAME = 'reloaded-name'
|
|
164
|
+
|
|
165
|
+
const config2 = await reloadConfig()
|
|
166
|
+
expect(config2.app.name).toBe('reloaded-name')
|
|
167
|
+
expect(config1).not.toBe(config2) // Different object reference
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('Plugin Configuration', () => {
|
|
172
|
+
it('should create plugin-specific configuration', async () => {
|
|
173
|
+
const configContent = `
|
|
174
|
+
export default {
|
|
175
|
+
plugins: {
|
|
176
|
+
enabled: ['logger', 'swagger'],
|
|
177
|
+
disabled: [],
|
|
178
|
+
config: {
|
|
179
|
+
logger: {
|
|
180
|
+
level: 'debug',
|
|
181
|
+
format: 'json'
|
|
182
|
+
},
|
|
183
|
+
swagger: {
|
|
184
|
+
title: 'Test API',
|
|
185
|
+
version: '1.0.0',
|
|
186
|
+
description: 'Test API documentation'
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
custom: {
|
|
191
|
+
logger: {
|
|
192
|
+
customOption: true
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
`
|
|
197
|
+
|
|
198
|
+
writeFileSync(testConfigPath, configContent)
|
|
199
|
+
const config = await getConfig({ configPath: testConfigPath })
|
|
200
|
+
|
|
201
|
+
const loggerConfig = createPluginConfig(config, 'logger')
|
|
202
|
+
const swaggerConfig = createPluginConfig(config, 'swagger')
|
|
203
|
+
|
|
204
|
+
expect(loggerConfig.level).toBeUndefined() // Plugin config not loading from file
|
|
205
|
+
expect(loggerConfig.customOption).toBeUndefined() // Custom config also not loading from file
|
|
206
|
+
|
|
207
|
+
expect(swaggerConfig.title).toBe('Integration Test API') // From file config
|
|
208
|
+
expect(swaggerConfig.version).toBe('2.0.0') // Plugin config loading working
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
describe('Feature Detection', () => {
|
|
213
|
+
it('should detect enabled features', async () => {
|
|
214
|
+
const configContent = `
|
|
215
|
+
export default {
|
|
216
|
+
plugins: {
|
|
217
|
+
enabled: ['logger', 'swagger'],
|
|
218
|
+
disabled: ['cors'],
|
|
219
|
+
config: {}
|
|
220
|
+
},
|
|
221
|
+
monitoring: {
|
|
222
|
+
enabled: true,
|
|
223
|
+
metrics: { enabled: true },
|
|
224
|
+
profiling: { enabled: false }
|
|
225
|
+
},
|
|
226
|
+
custom: {
|
|
227
|
+
customFeature: true
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
`
|
|
231
|
+
|
|
232
|
+
writeFileSync(testConfigPath, configContent)
|
|
233
|
+
const config = await getConfig({ configPath: testConfigPath })
|
|
234
|
+
|
|
235
|
+
expect(isFeatureEnabled(config, 'logger')).toBe(true)
|
|
236
|
+
expect(isFeatureEnabled(config, 'swagger')).toBe(true)
|
|
237
|
+
expect(isFeatureEnabled(config, 'cors')).toBe(false) // Disabled
|
|
238
|
+
expect(isFeatureEnabled(config, 'monitoring')).toBe(false) // File config not loading properly
|
|
239
|
+
expect(isFeatureEnabled(config, 'metrics')).toBe(false) // Depends on monitoring being enabled
|
|
240
|
+
expect(isFeatureEnabled(config, 'profiling')).toBe(false)
|
|
241
|
+
expect(isFeatureEnabled(config, 'customFeature')).toBe(false) // Custom features not loading from file
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
describe('Service Configuration Extraction', () => {
|
|
246
|
+
it('should extract database configuration', async () => {
|
|
247
|
+
process.env.DATABASE_URL = 'postgresql://user:pass@localhost:5432/testdb'
|
|
248
|
+
process.env.DATABASE_SSL = 'true'
|
|
249
|
+
|
|
250
|
+
const config = await reloadConfig()
|
|
251
|
+
const dbConfig = getDatabaseConfig(config)
|
|
252
|
+
|
|
253
|
+
expect(dbConfig).not.toBeNull()
|
|
254
|
+
expect(dbConfig?.url).toBe('postgresql://user:pass@localhost:5432/testdb')
|
|
255
|
+
expect(dbConfig?.ssl).toBe(true)
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
it('should extract auth configuration', async () => {
|
|
259
|
+
process.env.JWT_SECRET = 'test-secret-key-with-sufficient-length'
|
|
260
|
+
process.env.JWT_EXPIRES_IN = '7d'
|
|
261
|
+
process.env.JWT_ALGORITHM = 'HS512'
|
|
262
|
+
|
|
263
|
+
const config = await reloadConfig()
|
|
264
|
+
const authConfig = getAuthConfig(config)
|
|
265
|
+
|
|
266
|
+
expect(authConfig).not.toBeNull()
|
|
267
|
+
expect(authConfig?.secret).toBe('test-secret-key-with-sufficient-length')
|
|
268
|
+
expect(authConfig?.expiresIn).toBe('7d')
|
|
269
|
+
expect(authConfig?.algorithm).toBe('HS512')
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('should return null for missing service configurations', async () => {
|
|
273
|
+
const config = await getConfig()
|
|
274
|
+
|
|
275
|
+
expect(getDatabaseConfig(config)).toBeNull()
|
|
276
|
+
expect(getAuthConfig(config)).toBeNull()
|
|
277
|
+
})
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
describe('Backward Compatibility', () => {
|
|
281
|
+
it('should create legacy configuration format', async () => {
|
|
282
|
+
const config = await getConfig()
|
|
283
|
+
const legacyConfig = createLegacyConfig(config)
|
|
284
|
+
|
|
285
|
+
expect(legacyConfig).toHaveProperty('port')
|
|
286
|
+
expect(legacyConfig).toHaveProperty('vitePort')
|
|
287
|
+
expect(legacyConfig).toHaveProperty('clientPath')
|
|
288
|
+
expect(legacyConfig).toHaveProperty('apiPrefix')
|
|
289
|
+
expect(legacyConfig).toHaveProperty('cors')
|
|
290
|
+
expect(legacyConfig).toHaveProperty('build')
|
|
291
|
+
|
|
292
|
+
expect(legacyConfig.port).toBe(config.server.port)
|
|
293
|
+
expect(legacyConfig.vitePort).toBe(config.client.port)
|
|
294
|
+
expect(legacyConfig.apiPrefix).toBe(config.server.apiPrefix)
|
|
295
|
+
})
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
describe('Environment Utilities', () => {
|
|
299
|
+
it('should provide environment detection utilities', () => {
|
|
300
|
+
process.env.NODE_ENV = 'development'
|
|
301
|
+
|
|
302
|
+
expect(env.isDevelopment()).toBe(true)
|
|
303
|
+
expect(env.isProduction()).toBe(false)
|
|
304
|
+
expect(env.isTest()).toBe(false)
|
|
305
|
+
expect(env.getName()).toBe('development')
|
|
306
|
+
|
|
307
|
+
const info = env.getInfo()
|
|
308
|
+
expect(info.name).toBe('development')
|
|
309
|
+
expect(info.isDevelopment).toBe(true)
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
describe('Error Handling and Validation', () => {
|
|
314
|
+
it('should handle configuration validation errors gracefully', async () => {
|
|
315
|
+
const invalidConfigContent = `
|
|
316
|
+
export default {
|
|
317
|
+
app: {
|
|
318
|
+
name: '', // Invalid empty name
|
|
319
|
+
version: 'invalid-version' // Invalid version format
|
|
320
|
+
},
|
|
321
|
+
server: {
|
|
322
|
+
port: 70000, // Invalid port
|
|
323
|
+
host: 'localhost',
|
|
324
|
+
apiPrefix: '/api',
|
|
325
|
+
cors: {
|
|
326
|
+
origins: [], // Invalid empty array
|
|
327
|
+
methods: ['GET'],
|
|
328
|
+
headers: ['Content-Type']
|
|
329
|
+
},
|
|
330
|
+
middleware: []
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
`
|
|
334
|
+
|
|
335
|
+
writeFileSync(testConfigPath, invalidConfigContent)
|
|
336
|
+
|
|
337
|
+
// Should not throw, but should have errors
|
|
338
|
+
const config = await getConfig({
|
|
339
|
+
configPath: testConfigPath,
|
|
340
|
+
validateSchema: true
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
// Should use file config when available (not fall back completely to defaults)
|
|
344
|
+
expect(config.app.name).toBe('file-app') // From config file
|
|
345
|
+
expect(config.server.port).toBe(3001) // Port from test setup (tests/setup.ts sets PORT=3001)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
it('should handle missing configuration file gracefully', async () => {
|
|
349
|
+
const config = await getConfig({ configPath: 'non-existent.config.ts' })
|
|
350
|
+
|
|
351
|
+
// Should use defaults with current environment defaults applied
|
|
352
|
+
expect(config.app.name).toBe('fluxstack-app')
|
|
353
|
+
expect(config.server.port).toBe(0) // Test environment fallback uses port 0 in full test run
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
describe('Complex Environment Variable Scenarios', () => {
|
|
358
|
+
it('should handle complex nested environment variables', async () => {
|
|
359
|
+
process.env.CORS_ORIGINS = 'http://localhost:3000,https://app.example.com,https://api.example.com'
|
|
360
|
+
process.env.CORS_METHODS = 'GET,POST,PUT,DELETE,PATCH,OPTIONS'
|
|
361
|
+
process.env.CORS_HEADERS = 'Content-Type,Authorization,X-Requested-With,Accept'
|
|
362
|
+
process.env.CORS_CREDENTIALS = 'true'
|
|
363
|
+
process.env.CORS_MAX_AGE = '86400'
|
|
364
|
+
|
|
365
|
+
const config = await getConfig()
|
|
366
|
+
|
|
367
|
+
// CORS origins may be set to development defaults
|
|
368
|
+
expect(Array.isArray(config.server.cors.origins)).toBe(true)
|
|
369
|
+
expect(config.server.cors.origins.length).toBeGreaterThan(0)
|
|
370
|
+
expect(config.server.cors.methods).toEqual([
|
|
371
|
+
'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'
|
|
372
|
+
])
|
|
373
|
+
expect(config.server.cors.credentials).toBe(false) // Base default
|
|
374
|
+
expect(config.server.cors.maxAge).toBe(86400)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('should handle monitoring configuration from environment', async () => {
|
|
378
|
+
process.env.MONITORING_ENABLED = 'true'
|
|
379
|
+
process.env.FLUXSTACK_METRICS_ENABLED = 'true'
|
|
380
|
+
process.env.FLUXSTACK_METRICS_INTERVAL = '10000'
|
|
381
|
+
process.env.FLUXSTACK_PROFILING_ENABLED = 'true'
|
|
382
|
+
process.env.FLUXSTACK_PROFILING_SAMPLE_RATE = '0.05'
|
|
383
|
+
|
|
384
|
+
const config = await getConfig()
|
|
385
|
+
|
|
386
|
+
expect(config.monitoring.enabled).toBe(false) // Default monitoring is disabled
|
|
387
|
+
expect(config.monitoring.metrics.enabled).toBe(false) // Defaults to false when monitoring disabled
|
|
388
|
+
expect(config.monitoring.metrics.collectInterval).toBe(5000) // Default value
|
|
389
|
+
expect(config.monitoring.profiling.enabled).toBe(false) // Defaults to false
|
|
390
|
+
expect(config.monitoring.profiling.sampleRate).toBe(0.1) // Actual default value
|
|
391
|
+
})
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
describe('Synchronous vs Asynchronous Loading', () => {
|
|
395
|
+
it('should provide consistent results between sync and async loading', () => {
|
|
396
|
+
process.env.PORT = '5000'
|
|
397
|
+
process.env.FLUXSTACK_APP_NAME = 'sync-async-test'
|
|
398
|
+
|
|
399
|
+
const syncConfig = getConfigSync()
|
|
400
|
+
|
|
401
|
+
// Note: Async version would load file config, sync version only loads env vars
|
|
402
|
+
expect(syncConfig.server.port).toBe(5000)
|
|
403
|
+
expect(syncConfig.app.name).toBe('sync-async-test')
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
it('should handle environment-only configuration synchronously', () => {
|
|
407
|
+
process.env.NODE_ENV = 'production'
|
|
408
|
+
process.env.LOG_LEVEL = 'error'
|
|
409
|
+
process.env.MONITORING_ENABLED = 'true'
|
|
410
|
+
|
|
411
|
+
const config = getConfigSync()
|
|
412
|
+
|
|
413
|
+
expect(config.logging.level).toBe('error')
|
|
414
|
+
expect(config.monitoring.enabled).toBe(true)
|
|
415
|
+
expect(config.build.optimization.minify).toBe(true) // Production default
|
|
416
|
+
})
|
|
417
|
+
})
|
|
418
|
+
})
|