disclaw/tests/unit/workspace-root-resolve.test.ts
Nick Tabeling d71081d2b1 feat(config): move workspaces_root to home dir, add tilde expansion
- disclaw.yaml: change default workspaces_root to ~/.disclaw/workspaces
- src/config/loader.ts: add expandWorkspacesRoot() with ~ expansion via
  os.homedir(), path.resolve() normalisation, and in-repo warning via
  console.warn (explains CLAUDE.md walk-up leak risk)
- tests/unit/workspace-root-resolve.test.ts: Vitest unit tests (a-d)
- README.md: add Migration bestehender Workspaces section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 10:40:34 +02:00

63 lines
2.3 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import * as os from "os";
import * as path from "path";
import { expandWorkspacesRoot } from "../../src/config/loader";
const HOME = os.homedir();
// Use an absolute path that is portable across Linux, macOS, and Windows.
// os.tmpdir() always returns an absolute path on all platforms.
const REPO_ROOT = path.join(os.tmpdir(), "fake-disclaw-repo");
describe("expandWorkspacesRoot", () => {
beforeEach(() => {
vi.spyOn(console, "warn").mockImplementation(() => undefined);
});
afterEach(() => {
vi.restoreAllMocks();
});
it("(a) expands leading ~ to os.homedir() and resolves to absolute path", () => {
const result = expandWorkspacesRoot("~/.disclaw/workspaces", REPO_ROOT);
expect(result).toBe(path.resolve(HOME, ".disclaw", "workspaces"));
expect(path.isAbsolute(result)).toBe(true);
});
it("(a) expands ~ with no trailing path to os.homedir()", () => {
const result = expandWorkspacesRoot("~", REPO_ROOT);
expect(result).toBe(path.resolve(HOME));
});
it("(b) leaves an already-absolute path unchanged (no double expansion)", () => {
const absolute = path.join(HOME, ".disclaw", "workspaces");
const result = expandWorkspacesRoot(absolute, REPO_ROOT);
expect(result).toBe(absolute);
});
it("(c) resolves a relative path (without ~) against repoRoot to an absolute path", () => {
const result = expandWorkspacesRoot("myworkspaces", REPO_ROOT);
expect(result).toBe(path.join(REPO_ROOT, "myworkspaces"));
expect(path.isAbsolute(result)).toBe(true);
});
it("(d) triggers console.warn when workspaces_root is inside the repo", () => {
expandWorkspacesRoot("workspaces", REPO_ROOT);
expect(console.warn).toHaveBeenCalledOnce();
expect(console.warn).toHaveBeenCalledWith(
expect.stringContaining("[DisClaw] WARNING")
);
expect(console.warn).toHaveBeenCalledWith(
expect.stringContaining("CLAUDE.md")
);
});
it("(d) does NOT warn when workspaces_root is outside the repo", () => {
expandWorkspacesRoot("~/.disclaw/workspaces", REPO_ROOT);
expect(console.warn).not.toHaveBeenCalled();
});
it("(d) does NOT warn when an absolute path outside the repo is given", () => {
expandWorkspacesRoot("/tmp/disclaw-workspaces", REPO_ROOT);
expect(console.warn).not.toHaveBeenCalled();
});
});