fix: resolve test environment loading race condition in CI

- Move getTestConfig() calls from module level to test execution time
- Add CI-specific debug logging to diagnose environment loading issues
- Add verification step in CI workflow to check .env.test availability
- Ensure environment variables are loaded before tests access config

The issue was that config was being accessed at module import time,
which could happen before the global setup runs in some CI environments.
This commit is contained in:
czlonkowski
2025-07-29 07:13:37 +02:00
parent 6c40057cf4
commit a8c3d04c12
4 changed files with 80 additions and 30 deletions

View File

@@ -19,10 +19,14 @@ import {
} from '@tests/helpers/env-helpers';
describe('Test Environment Configuration Example', () => {
const config = getTestConfig();
const logger = createTestLogger('test-env-example');
let config: ReturnType<typeof getTestConfig>;
let logger: ReturnType<typeof createTestLogger>;
beforeAll(() => {
// Initialize config inside beforeAll to ensure environment is loaded
config = getTestConfig();
logger = createTestLogger('test-env-example');
logger.info('Test suite starting with configuration:', {
environment: config.nodeEnv,
database: config.database.path,
@@ -35,20 +39,23 @@ describe('Test Environment Configuration Example', () => {
});
it('should be in test mode', () => {
const testConfig = getTestConfig();
expect(isTestMode()).toBe(true);
expect(config.nodeEnv).toBe('test');
expect(config.isTest).toBe(true);
expect(testConfig.nodeEnv).toBe('test');
expect(testConfig.isTest).toBe(true);
});
it('should have proper database configuration', () => {
expect(config.database.path).toBeDefined();
expect(config.database.rebuildOnStart).toBe(false);
expect(config.database.seedData).toBe(true);
const testConfig = getTestConfig();
expect(testConfig.database.path).toBeDefined();
expect(testConfig.database.rebuildOnStart).toBe(false);
expect(testConfig.database.seedData).toBe(true);
});
it('should have mock API configuration', () => {
expect(config.api.url).toMatch(/mock-api/);
expect(config.api.key).toBe('test-api-key-12345');
const testConfig = getTestConfig();
expect(testConfig.api.url).toMatch(/mock-api/);
expect(testConfig.api.key).toBe('test-api-key-12345');
});
it('should respect test timeouts', { timeout: getTestTimeout('unit') }, async () => {
@@ -60,7 +67,8 @@ describe('Test Environment Configuration Example', () => {
});
it('should support environment overrides', () => {
const originalLogLevel = config.logging.level;
const testConfig = getTestConfig();
const originalLogLevel = testConfig.logging.level;
const result = withEnvOverrides({
LOG_LEVEL: 'debug',
@@ -73,7 +81,8 @@ describe('Test Environment Configuration Example', () => {
});
expect(result).toBe('success');
expect(config.logging.level).toBe(originalLogLevel);
const configAfter = getTestConfig();
expect(configAfter.logging.level).toBe(originalLogLevel);
});
it('should generate unique test database paths', () => {
@@ -87,15 +96,17 @@ describe('Test Environment Configuration Example', () => {
});
it('should construct mock API URLs', () => {
const testConfig = getTestConfig();
const baseUrl = getMockApiUrl();
const endpointUrl = getMockApiUrl('/nodes');
expect(baseUrl).toBe(config.api.url);
expect(endpointUrl).toBe(`${config.api.url}/nodes`);
expect(baseUrl).toBe(testConfig.api.url);
expect(endpointUrl).toBe(`${testConfig.api.url}/nodes`);
});
it.skipIf(!isFeatureEnabled('mockExternalApis'))('should check feature flags', () => {
expect(config.features.mockExternalApis).toBe(true);
const testConfig = getTestConfig();
expect(testConfig.features.mockExternalApis).toBe(true);
expect(isFeatureEnabled('mockExternalApis')).toBe(true);
});
@@ -135,9 +146,10 @@ describe('Test Environment Configuration Example', () => {
});
it('should have proper logging configuration', () => {
expect(config.logging.level).toBe('error');
expect(config.logging.debug).toBe(false);
expect(config.logging.showStack).toBe(true);
const testConfig = getTestConfig();
expect(testConfig.logging.level).toBe('error');
expect(testConfig.logging.debug).toBe(false);
expect(testConfig.logging.showStack).toBe(true);
// Logger should respect configuration
logger.debug('This should not appear in test output');
@@ -145,26 +157,30 @@ describe('Test Environment Configuration Example', () => {
});
it('should have performance thresholds', () => {
expect(config.performance.thresholds.apiResponse).toBe(100);
expect(config.performance.thresholds.dbQuery).toBe(50);
expect(config.performance.thresholds.nodeParse).toBe(200);
const testConfig = getTestConfig();
expect(testConfig.performance.thresholds.apiResponse).toBe(100);
expect(testConfig.performance.thresholds.dbQuery).toBe(50);
expect(testConfig.performance.thresholds.nodeParse).toBe(200);
});
it('should disable caching and rate limiting in tests', () => {
expect(config.cache.enabled).toBe(false);
expect(config.cache.ttl).toBe(0);
expect(config.rateLimiting.max).toBe(0);
expect(config.rateLimiting.window).toBe(0);
const testConfig = getTestConfig();
expect(testConfig.cache.enabled).toBe(false);
expect(testConfig.cache.ttl).toBe(0);
expect(testConfig.rateLimiting.max).toBe(0);
expect(testConfig.rateLimiting.window).toBe(0);
});
it('should configure test paths', () => {
expect(config.paths.fixtures).toBe('./tests/fixtures');
expect(config.paths.data).toBe('./tests/data');
expect(config.paths.snapshots).toBe('./tests/__snapshots__');
const testConfig = getTestConfig();
expect(testConfig.paths.fixtures).toBe('./tests/fixtures');
expect(testConfig.paths.data).toBe('./tests/data');
expect(testConfig.paths.snapshots).toBe('./tests/__snapshots__');
});
it('should support MSW configuration', () => {
expect(config.mocking.msw.enabled).toBe(true);
expect(config.mocking.msw.apiDelay).toBe(0);
const testConfig = getTestConfig();
expect(testConfig.mocking.msw.enabled).toBe(true);
expect(testConfig.mocking.msw.apiDelay).toBe(0);
});
});