diff --git a/apps/server/src/routes/worktree/routes/list-branches.ts b/apps/server/src/routes/worktree/routes/list-branches.ts index 9bd6f307..295c8242 100644 --- a/apps/server/src/routes/worktree/routes/list-branches.ts +++ b/apps/server/src/routes/worktree/routes/list-branches.ts @@ -38,8 +38,9 @@ export function createListBranchesHandler() { const currentBranch = currentBranchOutput.trim(); // List all local branches + // Use %(refname:short) without quotes - quotes are preserved on Windows const { stdout: branchesOutput } = await execAsync( - "git branch --format='%(refname:short)'", + "git branch --format=%(refname:short)", { cwd: worktreePath } ); @@ -47,11 +48,15 @@ export function createListBranchesHandler() { .trim() .split("\n") .filter((b) => b.trim()) - .map((name) => ({ - name: name.trim(), - isCurrent: name.trim() === currentBranch, - isRemote: false, - })); + .map((name) => { + // Remove any surrounding quotes (Windows git may preserve them) + const cleanName = name.trim().replace(/^['"]|['"]$/g, ""); + return { + name: cleanName, + isCurrent: cleanName === currentBranch, + isRemote: false, + }; + }); // Get ahead/behind count for current branch let aheadCount = 0; diff --git a/apps/ui/tests/context-view.spec.ts b/apps/ui/tests/context-view.spec.ts index dbc36d12..027593f7 100644 --- a/apps/ui/tests/context-view.spec.ts +++ b/apps/ui/tests/context-view.spec.ts @@ -22,7 +22,7 @@ import { } from "./utils"; const WORKSPACE_ROOT = path.resolve(process.cwd(), "../.."); -const TEST_IMAGE_SRC = path.join(WORKSPACE_ROOT, "apps/app/public/logo.png"); +const TEST_IMAGE_SRC = path.join(WORKSPACE_ROOT, "apps/ui/public/logo.png"); // Configure all tests to run serially to prevent interference with shared context directory test.describe.configure({ mode: "serial" }); diff --git a/apps/ui/tests/utils/git/worktree.ts b/apps/ui/tests/utils/git/worktree.ts index 4680eae8..647e3453 100644 --- a/apps/ui/tests/utils/git/worktree.ts +++ b/apps/ui/tests/utils/git/worktree.ts @@ -40,7 +40,7 @@ export interface FeatureData { */ function getWorkspaceRoot(): string { const cwd = process.cwd(); - if (cwd.includes("apps/app")) { + if (cwd.includes("apps/ui")) { return path.resolve(cwd, "../.."); } return cwd; @@ -180,7 +180,10 @@ export async function listWorktrees(repoPath: string): Promise { .slice(1) // Skip main worktree .map((block) => { const pathLine = block.split("\n").find((line) => line.startsWith("worktree ")); - return pathLine ? pathLine.replace("worktree ", "") : null; + if (!pathLine) return null; + // Normalize path separators to OS native (git on Windows returns forward slashes) + const worktreePath = pathLine.replace("worktree ", ""); + return path.normalize(worktreePath); }) .filter(Boolean) as string[]; } catch { diff --git a/apps/ui/tests/utils/project/fixtures.ts b/apps/ui/tests/utils/project/fixtures.ts index e1439199..89488411 100644 --- a/apps/ui/tests/utils/project/fixtures.ts +++ b/apps/ui/tests/utils/project/fixtures.ts @@ -3,11 +3,11 @@ import * as fs from "fs"; import * as path from "path"; /** - * Resolve the workspace root - handle both running from apps/app and from root + * Resolve the workspace root - handle both running from apps/ui and from root */ export function getWorkspaceRoot(): string { const cwd = process.cwd(); - if (cwd.includes("apps/app")) { + if (cwd.includes("apps/ui")) { return path.resolve(cwd, "../.."); } return cwd; diff --git a/apps/ui/tests/worktree-integration.spec.ts b/apps/ui/tests/worktree-integration.spec.ts index f1eccbb9..19fa80f3 100644 --- a/apps/ui/tests/worktree-integration.spec.ts +++ b/apps/ui/tests/worktree-integration.spec.ts @@ -830,7 +830,8 @@ test.describe("Worktree Integration Tests", () => { const featureFilePath = path.join(featuresDir, featureDir!, "feature.json"); const featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8")); expect(featureData.branchName).toBe(branchName); - expect(featureData.worktreePath).toBe(expectedWorktreePath); + // Normalize paths for comparison (server returns forward slashes, path.join returns native) + expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(expectedWorktreePath)); }); test("should reset feature branch and worktree when worktree is deleted", async ({ @@ -888,7 +889,8 @@ test.describe("Worktree Integration Tests", () => { let featureFilePath = path.join(featuresDir, featureDir!, "feature.json"); let featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8")); expect(featureData.branchName).toBe(branchName); - expect(featureData.worktreePath).toBe(worktreePath); + // Normalize paths for comparison (server returns forward slashes, path.join returns native) + expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(worktreePath)); // Delete the worktree via UI // Open the worktree actions menu @@ -2428,7 +2430,8 @@ test.describe("Worktree Integration Tests", () => { // Verify feature was updated with correct branch and worktreePath featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8")); expect(featureData.branchName).toBe(newBranchName); - expect(featureData.worktreePath).toBe(expectedWorktreePath); + // Normalize paths for comparison (server returns forward slashes, path.join returns native) + expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(expectedWorktreePath)); }); test("should not create worktree when editing a feature and selecting main branch", async ({ @@ -2586,6 +2589,7 @@ test.describe("Worktree Integration Tests", () => { const featureFilePath = path.join(featuresDir, featureDir!, "feature.json"); const featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8")); expect(featureData.branchName).toBe(existingBranch); - expect(featureData.worktreePath).toBe(existingWorktreePath); + // Normalize paths for comparison (server returns forward slashes, path.join returns native) + expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(existingWorktreePath)); }); });