/** * Unit tests for TokenConfigLoader */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { TokenConfigLoader, TokenConfig, DefaultConfigLoader, DefaultConfig } from '../../src/config.js'; describe('TokenConfigLoader', () => { const originalEnv = { ...process.env }; beforeEach(() => { process.env = { ...originalEnv }; delete process.env.BITBUCKET_MCP_TOKEN; delete process.env.DEFAULT_WORKSPACE; delete process.env.DEFAULT_REPO; }); afterEach(() => { process.env = originalEnv; vi.restoreAllMocks(); }); describe('token validation', () => { it('should accept valid tokens (alphanumeric with special chars)', () => { const validPattern = /^[A-Za-z0-9=._-]+$/; expect(validPattern.test('abc123def45678901234567')).toBe(true); expect(validPattern.test('ATBB1234567890abcdefgh')).toBe(true); expect(validPattern.test('Bearer_token.with=chars12')).toBe(true); expect(validPattern.test('a'.repeat(20))).toBe(true); }); it('should reject tokens that are too short', () => { const shortToken = 'abc123'; expect(shortToken.length).toBeLessThan(20); }); it('should reject tokens with invalid characters', () => { const invalidToken = 'token with spaces!@#$%'; const validPattern = /^[A-Za-z0-9=._-]+$/; expect(validPattern.test(invalidToken)).toBe(false); }); }); describe('environment variable loading', () => { it('should load token from BITBUCKET_MCP_TOKEN env var', async () => { process.env.BITBUCKET_MCP_EMAIL = 'test@example.com'; process.env.BITBUCKET_MCP_TOKEN = 'valid_test_token_12345678901234567'; const config = await TokenConfigLoader.load(); expect(config.token).toBe('valid_test_token_12345678901234567'); expect(config.source).toBe('env'); }); }); describe('TokenConfig interface', () => { it('should return correct config structure for env source', async () => { process.env.BITBUCKET_MCP_TOKEN = 'test_token_12345678901234567'; const config = await TokenConfigLoader.load(); expect(config).toHaveProperty('token'); expect(config).toHaveProperty('source'); expect(['env', 'dotenv', 'prompt']).toContain(config.source); }); }); }); describe('DefaultConfigLoader', () => { const originalEnv = { ...process.env }; beforeEach(() => { process.env = { ...originalEnv }; delete process.env.DEFAULT_WORKSPACE; delete process.env.DEFAULT_REPO; }); afterEach(() => { process.env = originalEnv; }); describe('load', () => { it('should return null values when env vars are not set', () => { const config = DefaultConfigLoader.load(); expect(config.workspace).toBeNull(); expect(config.repo).toBeNull(); }); it('should return workspace and repo from env vars when set', () => { process.env.DEFAULT_WORKSPACE = 'my-workspace'; process.env.DEFAULT_REPO = 'my-repo'; const config = DefaultConfigLoader.load(); expect(config.workspace).toBe('my-workspace'); expect(config.repo).toBe('my-repo'); }); it('should return partial config when only workspace is set', () => { process.env.DEFAULT_WORKSPACE = 'only-workspace'; const config = DefaultConfigLoader.load(); expect(config.workspace).toBe('only-workspace'); expect(config.repo).toBeNull(); }); it('should return partial config when only repo is set', () => { process.env.DEFAULT_REPO = 'only-repo'; const config = DefaultConfigLoader.load(); expect(config.workspace).toBeNull(); expect(config.repo).toBe('only-repo'); }); }); describe('getWorkspace', () => { it('should return null when DEFAULT_WORKSPACE is not set', () => { expect(DefaultConfigLoader.getWorkspace()).toBeNull(); }); it('should return workspace value when set', () => { process.env.DEFAULT_WORKSPACE = 'test-workspace'; expect(DefaultConfigLoader.getWorkspace()).toBe('test-workspace'); }); }); describe('getRepo', () => { it('should return null when DEFAULT_REPO is not set', () => { expect(DefaultConfigLoader.getRepo()).toBeNull(); }); it('should return repo value when set', () => { process.env.DEFAULT_REPO = 'test-repo'; expect(DefaultConfigLoader.getRepo()).toBe('test-repo'); }); }); });