import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { join } from "node:path"; import { Core } from "../core/backlog.ts"; import type { BacklogConfig } from "../types/index.ts"; import { createUniqueTestDir, safeCleanup } from "./test-utils.ts"; describe("Enhanced init command", () => { let tmpDir: string; beforeEach(async () => { tmpDir = createUniqueTestDir("test-enhanced-init"); }); afterEach(async () => { try { await safeCleanup(tmpDir); } catch { // Ignore cleanup errors - the unique directory names prevent conflicts } }); test("should detect existing project and preserve config during re-initialization", async () => { const core = new Core(tmpDir); // First initialization await core.initializeProject("Test Project"); // Verify initial config const initialConfig = await core.filesystem.loadConfig(); expect(initialConfig?.projectName).toBe("Test Project"); expect(initialConfig?.autoCommit).toBe(false); // Modify some config values to test preservation expect(initialConfig).toBeTruthy(); if (!initialConfig) throw new Error("Config not loaded"); const modifiedConfig: BacklogConfig = { ...initialConfig, projectName: initialConfig?.projectName ?? "Test Project", autoCommit: true, defaultEditor: "vim", defaultPort: 8080, }; await core.filesystem.saveConfig(modifiedConfig); // Re-initialization should detect existing config const existingConfig = await core.filesystem.loadConfig(); expect(existingConfig).toBeTruthy(); expect(existingConfig?.projectName).toBe("Test Project"); expect(existingConfig?.autoCommit).toBe(true); expect(existingConfig?.defaultEditor).toBe("vim"); expect(existingConfig?.defaultPort).toBe(8080); // Verify backlog structure exists const configExists = await Bun.file(join(tmpDir, "backlog", "config.yml")).exists(); expect(configExists).toBe(true); }); test("should create default config for new project initialization", async () => { const core = new Core(tmpDir); // Check that no config exists initially const initialConfig = await core.filesystem.loadConfig(); expect(initialConfig).toBeNull(); // Initialize project await core.initializeProject("New Project"); // Verify config was created with defaults const config = await core.filesystem.loadConfig(); expect(config).toBeTruthy(); expect(config?.projectName).toBe("New Project"); expect(config?.autoCommit).toBe(false); // Default value expect(config?.statuses).toEqual(["To Do", "In Progress", "Done"]); expect(config?.dateFormat).toBe("yyyy-mm-dd"); }); test("should handle editor configuration in init flow", async () => { const core = new Core(tmpDir); // Test that editor can be set and saved const configWithEditor = { projectName: "Editor Test Project", statuses: ["To Do", "In Progress", "Done"], labels: [], milestones: [], defaultStatus: "To Do", dateFormat: "yyyy-mm-dd", backlogDirectory: "backlog", autoCommit: false, remoteOperations: true, defaultEditor: "code --wait", }; await core.filesystem.ensureBacklogStructure(); await core.filesystem.saveConfig(configWithEditor); // Verify editor was saved const loadedConfig = await core.filesystem.loadConfig(); expect(loadedConfig?.defaultEditor).toBe("code --wait"); }); test("should handle config with missing fields by filling defaults", async () => { const core = new Core(tmpDir); // Create a minimal config (like from an older version) const minimalConfig = { projectName: "Legacy Project", statuses: ["To Do", "Done"], labels: [], milestones: [], defaultStatus: "To Do", dateFormat: "yyyy-mm-dd", }; await core.filesystem.ensureBacklogStructure(); await core.filesystem.saveConfig(minimalConfig); // Load config - should handle missing fields gracefully const loadedConfig = await core.filesystem.loadConfig(); expect(loadedConfig).toBeTruthy(); expect(loadedConfig?.projectName).toBe("Legacy Project"); expect(loadedConfig?.autoCommit).toBeUndefined(); // Missing fields should be undefined, not cause errors }); test("should preserve existing statuses and labels during re-initialization", async () => { const core = new Core(tmpDir); // Initialize with custom config const customConfig = { projectName: "Custom Project", statuses: ["Backlog", "In Progress", "Review", "Done"], labels: ["bug", "feature", "enhancement"], milestones: ["v1.0", "v2.0"], defaultStatus: "Backlog", dateFormat: "dd/mm/yyyy", maxColumnWidth: 30, backlogDirectory: "backlog", autoCommit: true, }; await core.filesystem.ensureBacklogStructure(); await core.filesystem.saveConfig(customConfig); // Simulate re-initialization by loading existing config const existingConfig = await core.filesystem.loadConfig(); expect(existingConfig).toBeTruthy(); expect(existingConfig?.statuses).toEqual(["Backlog", "In Progress", "Review", "Done"]); expect(existingConfig?.labels).toEqual(["bug", "feature", "enhancement"]); expect(existingConfig?.milestones).toEqual(["v1.0", "v2.0"]); expect(existingConfig?.dateFormat).toBe("dd/mm/yyyy"); expect(existingConfig?.maxColumnWidth).toBe(30); }); test("should handle zero-padding configuration in init flow", async () => { const core = new Core(tmpDir); // Test config with zero-padding enabled const configWithPadding = { projectName: "Padded Project", statuses: ["To Do", "In Progress", "Done"], labels: [], milestones: [], defaultStatus: "To Do", dateFormat: "yyyy-mm-dd", backlogDirectory: "backlog", autoCommit: false, remoteOperations: true, zeroPaddedIds: 3, }; await core.filesystem.ensureBacklogStructure(); await core.filesystem.saveConfig(configWithPadding); // Verify zero-padding was saved const loadedConfig = await core.filesystem.loadConfig(); expect(loadedConfig?.zeroPaddedIds).toBe(3); // Test that zero-padding config is available for ID generation // (ID generation happens in CLI, not in Core.createTask) expect(loadedConfig?.zeroPaddedIds).toBe(3); }); test("should handle zero-padding disabled configuration", async () => { const core = new Core(tmpDir); // Test config with zero-padding disabled const configWithoutPadding = { projectName: "Non-Padded Project", statuses: ["To Do", "In Progress", "Done"], labels: [], milestones: [], defaultStatus: "To Do", dateFormat: "yyyy-mm-dd", backlogDirectory: "backlog", autoCommit: false, remoteOperations: true, zeroPaddedIds: 0, }; await core.filesystem.ensureBacklogStructure(); await core.filesystem.saveConfig(configWithoutPadding); // Verify zero-padding was saved as disabled const loadedConfig = await core.filesystem.loadConfig(); expect(loadedConfig?.zeroPaddedIds).toBe(0); // Test that zero-padding is properly disabled // (ID generation happens in CLI, not in Core.createTask) expect(loadedConfig?.zeroPaddedIds).toBe(0); }); test("should preserve existing zero-padding config during re-initialization", async () => { const core = new Core(tmpDir); // Create initial config with padding const initialConfig = { projectName: "Test Project", statuses: ["To Do", "In Progress", "Done"], labels: [], milestones: [], defaultStatus: "To Do", dateFormat: "yyyy-mm-dd", backlogDirectory: "backlog", autoCommit: false, zeroPaddedIds: 4, }; await core.filesystem.ensureBacklogStructure(); await core.filesystem.saveConfig(initialConfig); // Simulate re-initialization by loading existing config const existingConfig = await core.filesystem.loadConfig(); expect(existingConfig).toBeTruthy(); expect(existingConfig?.zeroPaddedIds).toBe(4); // Verify the padding config is preserved // (ID generation happens in CLI, not in Core.createTask) expect(existingConfig?.zeroPaddedIds).toBe(4); }); });