backlog-md/src/test/enhanced-init.test.ts

241 lines
7.8 KiB
TypeScript

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);
});
});