241 lines
7.8 KiB
TypeScript
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);
|
|
});
|
|
});
|