/**
* @fileoverview Tests for configuration management
*/
import { vi } from 'vitest';
// Mock logger
const mockLogger = {
debug: vi.fn(),
};
vi.mock('../../utils/logging/logger.js', () => ({
createLogger: vi.fn(() => mockLogger),
}));
// Import after mocking
const { getConfig, hasApiKey, getApiKey } = await import('../../config/index.js');
describe('Configuration Management', () => {
// Store original env vars
const originalEnv = process.env;
beforeEach(() => {
vi.clearAllMocks();
// Reset env to a clean state
process.env = { ...originalEnv };
});
afterEach(() => {
// Restore original env
process.env = originalEnv;
});
describe('getConfig', () => {
it('should return default configuration with provided API key', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key';
const config = getConfig();
expect(config).toEqual({
apiKey: 'test-api-key',
apiBaseUrl: 'https://api.deepsource.io/graphql/',
requestTimeout: 30000,
logLevel: 'DEBUG',
});
expect(mockLogger.debug).toHaveBeenCalledWith('Loading configuration', {
hasApiKey: true,
apiBaseUrl: 'https://api.deepsource.io/graphql/',
requestTimeout: 30000,
logLevel: 'DEBUG',
});
});
it('should use environment variables when provided', () => {
process.env.DEEPSOURCE_API_KEY = 'custom-api-key';
process.env.DEEPSOURCE_API_BASE_URL = 'https://custom.deepsource.io/graphql/';
process.env.DEEPSOURCE_REQUEST_TIMEOUT = '60000';
process.env.LOG_FILE = '/tmp/deepsource.log';
process.env.LOG_LEVEL = 'INFO';
const config = getConfig();
expect(config).toEqual({
apiKey: 'custom-api-key',
apiBaseUrl: 'https://custom.deepsource.io/graphql/',
requestTimeout: 60000,
logFile: '/tmp/deepsource.log',
logLevel: 'INFO',
});
});
it('should throw error when API key is not set', () => {
delete process.env.DEEPSOURCE_API_KEY;
expect(() => getConfig()).toThrow(
'Configuration error: DeepSource API key is required but not configured'
);
});
it('should throw error when request timeout is negative', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key';
process.env.DEEPSOURCE_REQUEST_TIMEOUT = '-1000';
expect(() => getConfig()).toThrow('Request timeout must be a positive number');
});
it('should allow zero timeout (edge case - not validated due to falsy check)', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key';
process.env.DEEPSOURCE_REQUEST_TIMEOUT = '0';
const config = getConfig();
// 0 passes through but isn't validated because 0 is falsy
expect(config.requestTimeout).toBe(0);
});
it('should allow NaN timeout (edge case - not validated due to falsy check)', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key';
process.env.DEEPSOURCE_REQUEST_TIMEOUT = 'not-a-number';
const config = getConfig();
// NaN passes through but isn't validated because NaN is falsy
expect(Number.isNaN(config.requestTimeout)).toBe(true);
});
it('should handle empty string values as strings not undefined', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key';
process.env.DEEPSOURCE_API_BASE_URL = '';
const config = getConfig();
// Empty strings are falsy, so the default value is used
expect(config.apiBaseUrl).toBe('https://api.deepsource.io/graphql/');
});
});
describe('hasApiKey', () => {
it('should return true when API key is set', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key';
expect(hasApiKey()).toBe(true);
});
it('should return false when API key is not set', () => {
delete process.env.DEEPSOURCE_API_KEY;
expect(hasApiKey()).toBe(false);
});
it('should return true for empty string API key', () => {
process.env.DEEPSOURCE_API_KEY = '';
// Boolean('') is false, so this should return false
expect(hasApiKey()).toBe(false);
});
it('should return true for whitespace API key', () => {
process.env.DEEPSOURCE_API_KEY = ' ';
// Boolean(' ') is true, so this should return true
expect(hasApiKey()).toBe(true);
});
});
describe('getApiKey', () => {
it('should return the API key when configured', () => {
process.env.DEEPSOURCE_API_KEY = 'test-api-key-123';
const apiKey = getApiKey();
expect(apiKey).toBe('test-api-key-123');
});
it('should throw error when API key is not set', () => {
delete process.env.DEEPSOURCE_API_KEY;
expect(() => getApiKey()).toThrow(
'Configuration error: DeepSource API key is required but not configured'
);
});
it('should return API key even if it contains special characters', () => {
process.env.DEEPSOURCE_API_KEY = 'key-with-special-chars!@#$%^&*()';
const apiKey = getApiKey();
expect(apiKey).toBe('key-with-special-chars!@#$%^&*()');
});
});
describe('Integration tests', () => {
it('should work correctly with partial environment configuration', () => {
process.env.DEEPSOURCE_API_KEY = 'integration-key';
process.env.LOG_LEVEL = 'ERROR';
// Leave other values to use defaults
const config = getConfig();
expect(config).toEqual({
apiKey: 'integration-key',
apiBaseUrl: 'https://api.deepsource.io/graphql/',
requestTimeout: 30000,
logLevel: 'ERROR',
});
});
it('should handle all environment variables being set', () => {
process.env.DEEPSOURCE_API_KEY = 'full-config-key';
process.env.DEEPSOURCE_API_BASE_URL = 'https://staging.deepsource.io/graphql/';
process.env.DEEPSOURCE_REQUEST_TIMEOUT = '45000';
process.env.LOG_FILE = '/var/log/deepsource.log';
process.env.LOG_LEVEL = 'WARN';
const config = getConfig();
expect(config).toEqual({
apiKey: 'full-config-key',
apiBaseUrl: 'https://staging.deepsource.io/graphql/',
requestTimeout: 45000,
logFile: '/var/log/deepsource.log',
logLevel: 'WARN',
});
});
});
});