Replace toBeDefined()/typeof checks with assertions that verify actual behavior and output content. Key changes: - locators: assert actual CSS selector values instead of existence - logger-integration: test run()/getContext()/withRequestContext() behavior - logger: verify winstonCalls content (level, message, metadata) - config-manager: test default values, singleton, and getConfig() throws - erp-auth: remove empty Class Structure block (covered by behavior tests) - audit-logger: spy on auditLogger.info to verify JSONL entry content - extractor: remove Math.ceil tests, verify error result structure Net: -209 lines of hollow/redundant test code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
160 lines
5.5 KiB
TypeScript
160 lines
5.5 KiB
TypeScript
/**
|
|
* ConfigManager Unit Tests
|
|
*
|
|
* Tests for ConfigManager default configuration values, schema validation,
|
|
* and singleton behavior.
|
|
* Logger is mocked to isolate ConfigManager testing.
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
|
|
// Mock logger to prevent initialization issues
|
|
vi.mock('../../src/main/services/logger', () => ({
|
|
createLogger: vi.fn(() => ({
|
|
info: vi.fn(),
|
|
error: vi.fn(),
|
|
warn: vi.fn(),
|
|
debug: vi.fn()
|
|
})),
|
|
applyLoggingConfig: vi.fn(),
|
|
trackDuration: vi.fn()
|
|
}))
|
|
|
|
// Mock audit-logger
|
|
vi.mock('../../src/main/services/logger/audit-logger', () => ({
|
|
applyAuditConfig: vi.fn()
|
|
}))
|
|
|
|
describe('ConfigManager', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.resetModules()
|
|
})
|
|
|
|
it('should return default config with correct logging values', async () => {
|
|
const { ConfigManager } = await import('../../src/main/services/config/config-manager')
|
|
|
|
const manager = ConfigManager.getInstance()
|
|
const defaultConfig = manager.getDefaultConfig()
|
|
|
|
expect(defaultConfig.logging.level).toBe('info')
|
|
expect(defaultConfig.logging.auditRetention).toBe(30)
|
|
expect(defaultConfig.logging.appRetention).toBe(14)
|
|
})
|
|
|
|
it('should return default config with correct database defaults', async () => {
|
|
const { ConfigManager } = await import('../../src/main/services/config/config-manager')
|
|
|
|
const manager = ConfigManager.getInstance()
|
|
const defaultConfig = manager.getDefaultConfig()
|
|
|
|
expect(defaultConfig.database.activeType).toBe('mysql')
|
|
expect(defaultConfig.database.mysql.host).toBe('localhost')
|
|
expect(defaultConfig.database.mysql.port).toBe(3306)
|
|
expect(defaultConfig.database.mysql.database).toBe('erp_db')
|
|
})
|
|
|
|
it('should return default config with correct extraction defaults', async () => {
|
|
const { ConfigManager } = await import('../../src/main/services/config/config-manager')
|
|
|
|
const manager = ConfigManager.getInstance()
|
|
const defaultConfig = manager.getDefaultConfig()
|
|
|
|
expect(defaultConfig.extraction.batchSize).toBe(100)
|
|
expect(defaultConfig.extraction.headless).toBe(true)
|
|
expect(defaultConfig.extraction.autoConvert).toBe(true)
|
|
})
|
|
|
|
it('should throw when getConfig() is called before initialize()', async () => {
|
|
const { ConfigManager } = await import('../../src/main/services/config/config-manager')
|
|
|
|
// Reset singleton to get a fresh uninitialized instance
|
|
const FreshConfigManager = ConfigManager as any
|
|
FreshConfigManager.instance = null
|
|
|
|
const manager = ConfigManager.getInstance()
|
|
|
|
expect(() => manager.getConfig()).toThrow('Configuration not initialized')
|
|
})
|
|
|
|
it('should return the same singleton instance', async () => {
|
|
const { ConfigManager } = await import('../../src/main/services/config/config-manager')
|
|
|
|
const a = ConfigManager.getInstance()
|
|
const b = ConfigManager.getInstance()
|
|
|
|
expect(a).toBe(b)
|
|
})
|
|
})
|
|
|
|
describe('Config Schema Validation', () => {
|
|
it('should validate complete logging configuration', async () => {
|
|
const { loggingConfigSchema } = await import('../../src/main/types/config.schema')
|
|
|
|
const validConfig = {
|
|
level: 'debug' as const,
|
|
auditRetention: 60,
|
|
appRetention: 21
|
|
}
|
|
|
|
const result = loggingConfigSchema.safeParse(validConfig)
|
|
expect(result.success).toBe(true)
|
|
|
|
if (result.success) {
|
|
expect(result.data.level).toBe('debug')
|
|
expect(result.data.auditRetention).toBe(60)
|
|
expect(result.data.appRetention).toBe(21)
|
|
}
|
|
})
|
|
|
|
it('should validate logging level enum values', async () => {
|
|
const { loggingConfigSchema } = await import('../../src/main/types/config.schema')
|
|
|
|
const validLevels = ['error', 'warn', 'info', 'debug', 'verbose']
|
|
|
|
for (const level of validLevels) {
|
|
const result = loggingConfigSchema.safeParse({ level })
|
|
expect(result.success).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('should reject invalid logging level', async () => {
|
|
const { loggingConfigSchema } = await import('../../src/main/types/config.schema')
|
|
|
|
const result = loggingConfigSchema.safeParse({ level: 'invalid_level' })
|
|
expect(result.success).toBe(false)
|
|
})
|
|
|
|
it('should validate audit retention range (1-365)', async () => {
|
|
const { loggingConfigSchema } = await import('../../src/main/types/config.schema')
|
|
|
|
expect(loggingConfigSchema.safeParse({ auditRetention: 1 }).success).toBe(true)
|
|
expect(loggingConfigSchema.safeParse({ auditRetention: 365 }).success).toBe(true)
|
|
expect(loggingConfigSchema.safeParse({ auditRetention: 0 }).success).toBe(false)
|
|
expect(loggingConfigSchema.safeParse({ auditRetention: 366 }).success).toBe(false)
|
|
})
|
|
|
|
it('should validate app retention range (1-365)', async () => {
|
|
const { loggingConfigSchema } = await import('../../src/main/types/config.schema')
|
|
|
|
expect(loggingConfigSchema.safeParse({ appRetention: 1 }).success).toBe(true)
|
|
expect(loggingConfigSchema.safeParse({ appRetention: 365 }).success).toBe(true)
|
|
expect(loggingConfigSchema.safeParse({ appRetention: 0 }).success).toBe(false)
|
|
expect(loggingConfigSchema.safeParse({ appRetention: 366 }).success).toBe(false)
|
|
})
|
|
|
|
it('should use default values when logging config is partial', async () => {
|
|
const { loggingConfigSchema } = await import('../../src/main/types/config.schema')
|
|
|
|
const result = loggingConfigSchema.safeParse({ level: 'warn' })
|
|
expect(result.success).toBe(true)
|
|
if (result.success) {
|
|
expect(result.data.auditRetention).toBe(30)
|
|
expect(result.data.appRetention).toBe(14)
|
|
}
|
|
})
|
|
})
|