env.test.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import assert from 'node:assert/strict';
  2. import test from 'node:test';
  3. import { EnvironmentConfigurationError, loadConfig } from '../src/config/env.js';
  4. const validEnvironment: NodeJS.ProcessEnv = {
  5. NODE_ENV: 'test',
  6. HOST: '127.0.0.1',
  7. PORT: '4400',
  8. DATABASE_URL: 'postgres://user:password@127.0.0.1:5432/saas_voc',
  9. MIGRATION_DATABASE_URL: 'postgres://owner:password@127.0.0.1:5432/saas_voc',
  10. PARSE_APP_ID: 'test-app-id',
  11. PARSE_MASTER_KEY: 'a'.repeat(32),
  12. PARSE_MAINTENANCE_KEY: 'b'.repeat(32),
  13. PARSE_SERVER_URL: 'http://127.0.0.1:4400/parse',
  14. API_AUTH_MODE: 'disabled',
  15. FMODE_BASE_URL: 'http://127.0.0.1:3000/api/voc-e-commerce',
  16. FMODE_API_KEY: 'test-key',
  17. CORS_ORIGINS: 'http://127.0.0.1:4300',
  18. };
  19. test('loadConfig rejects missing secrets before startup', () => {
  20. const environment = { ...validEnvironment };
  21. delete environment.DATABASE_URL;
  22. delete environment.PARSE_MASTER_KEY;
  23. delete environment.PARSE_MAINTENANCE_KEY;
  24. delete environment.FMODE_API_KEY;
  25. assert.throws(
  26. () => loadConfig(environment),
  27. (error: unknown) => {
  28. assert.ok(error instanceof EnvironmentConfigurationError);
  29. assert.match(error.message, /DATABASE_URL/);
  30. assert.match(error.message, /PARSE_MASTER_KEY/);
  31. assert.match(error.message, /PARSE_MAINTENANCE_KEY/);
  32. assert.match(error.message, /FMODE_API_KEY/);
  33. return true;
  34. },
  35. );
  36. });
  37. test('loadConfig normalizes URLs and CORS origins', () => {
  38. const config = loadConfig({
  39. ...validEnvironment,
  40. FMODE_BASE_URL: 'http://127.0.0.1:3000/api/voc-e-commerce/',
  41. CORS_ORIGINS: 'http://127.0.0.1:4300, http://localhost:4200',
  42. });
  43. assert.equal(config.fmode.baseUrl, 'http://127.0.0.1:3000/api/voc-e-commerce');
  44. assert.equal(config.ai.baseUrl, 'https://api.fmode.cn');
  45. assert.equal(config.ai.defaultModel, 'deepseek-v4-pro');
  46. assert.equal(config.ai.token, '');
  47. assert.equal(config.database.migrationUrl, validEnvironment.MIGRATION_DATABASE_URL);
  48. assert.equal(config.worker.enabled, true);
  49. assert.equal(config.worker.staleAfterMs, 900_000);
  50. assert.equal(config.worker.reviewMaxPages, 1);
  51. assert.equal(config.auth.mode, 'disabled');
  52. assert.equal(config.auth.defaultWorkspaceId, 'demashi');
  53. assert.equal(config.listingAi.jdVocEnabled, false);
  54. assert.equal(config.listingAi.jdVocAiEnabled, false);
  55. assert.equal(config.listingAi.jdVocImageShadowEnabled, false);
  56. assert.equal(config.listingAi.jdVocDisplayDefault, false);
  57. assert.equal(config.listingAi.jdVocAiModel, 'gpt-4o-mini');
  58. assert.deepEqual(config.corsOrigins, ['http://127.0.0.1:4300', 'http://localhost:4200']);
  59. });
  60. test('loadConfig enables each approved JD-VOC rollout switch independently', () => {
  61. const config = loadConfig({ ...validEnvironment, JD_VOC_ENABLED:'true', JD_VOC_AI_ENABLED:'true', JD_VOC_IMAGE_SHADOW_ENABLED:'true', JD_VOC_DISPLAY_DEFAULT:'true' });
  62. assert.equal(config.listingAi.jdVocEnabled, true);
  63. assert.equal(config.listingAi.jdVocAiEnabled, true);
  64. assert.equal(config.listingAi.jdVocImageShadowEnabled, true);
  65. assert.equal(config.listingAi.jdVocDisplayDefault, true);
  66. });
  67. test('loadConfig treats blank optional environment values as unset', () => {
  68. const config = loadConfig({
  69. ...validEnvironment,
  70. MIGRATION_DATABASE_URL: '',
  71. SAAS_BOOTSTRAP_ADMIN_USER_ID: '',
  72. });
  73. assert.equal(config.database.migrationUrl, validEnvironment.DATABASE_URL);
  74. assert.equal(config.auth.bootstrapAdminUserId, '');
  75. });
  76. test('loadConfig supports Parse REST storage without a direct database connection', () => {
  77. const environment: NodeJS.ProcessEnv = { ...validEnvironment, STORAGE_DRIVER: 'parse_rest' };
  78. delete environment.DATABASE_URL;
  79. delete environment.MIGRATION_DATABASE_URL;
  80. delete environment.PARSE_MAINTENANCE_KEY;
  81. environment.PARSE_APP_ID = 'dev';
  82. environment.PARSE_MASTER_KEY = 'short-test-key';
  83. environment.PARSE_SERVER_URL = 'http://dev.example.test/parse';
  84. const config = loadConfig(environment);
  85. assert.equal(config.storageDriver, 'parse_rest');
  86. assert.equal(config.database.url, '');
  87. assert.equal(config.parse.serverUrl, 'http://dev.example.test/parse');
  88. });
  89. test('loadConfig rejects disabled authentication in production', () => {
  90. assert.throws(
  91. () => loadConfig({ ...validEnvironment, NODE_ENV: 'production', API_AUTH_MODE: 'disabled' }),
  92. (error: unknown) => error instanceof EnvironmentConfigurationError
  93. && error.message.includes('disabled authentication is not allowed in production'),
  94. );
  95. });