mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
Merge main into refactor/frontend
Merge latest features from main including: - PR #161 (worktree-confusion): Clarified branch handling in dialogs - PR #160 (speckits-rebase): Planning mode functionality Resolved conflicts: - add-feature-dialog.tsx: Combined TanStack Router navigation with branch selection state - worktree-integration.spec.ts: Updated tests for new worktree behavior (created at execution time) - package-lock.json: Regenerated after merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -741,14 +741,15 @@ test.describe("Worktree Integration Tests", () => {
|
||||
await waitForNetworkIdle(page);
|
||||
await waitForBoardView(page);
|
||||
|
||||
// Create a worktree first
|
||||
// Note: Worktrees are created at execution time (when feature starts),
|
||||
// not when adding to backlog. We can specify a branch name without
|
||||
// creating a worktree first.
|
||||
const branchName = "feature/test-branch";
|
||||
await apiCreateWorktree(page, testRepo.path, branchName);
|
||||
|
||||
// Click add feature button
|
||||
await clickAddFeature(page);
|
||||
|
||||
// Fill in the feature details
|
||||
// Fill in the feature details with a branch name
|
||||
await fillAddFeatureDialog(page, "Test feature for worktree", {
|
||||
branch: branchName,
|
||||
category: "Testing",
|
||||
@@ -773,9 +774,12 @@ test.describe("Worktree Integration Tests", () => {
|
||||
expect(featureData.description).toBe("Test feature for worktree");
|
||||
expect(featureData.branchName).toBe(branchName);
|
||||
expect(featureData.status).toBe("backlog");
|
||||
// Verify worktreePath is not set when adding to backlog
|
||||
// (worktrees are created at execution time, not when adding to backlog)
|
||||
expect(featureData.worktreePath).toBeUndefined();
|
||||
});
|
||||
|
||||
test("should create worktree automatically when adding feature with new branch", async ({
|
||||
test("should store branch name when adding feature with new branch (worktree created at execution)", async ({
|
||||
page,
|
||||
}) => {
|
||||
await setupProjectWithPath(page, testRepo.path);
|
||||
@@ -783,12 +787,13 @@ test.describe("Worktree Integration Tests", () => {
|
||||
await waitForNetworkIdle(page);
|
||||
await waitForBoardView(page);
|
||||
|
||||
// Use a branch name that doesn't exist yet - NO worktree is pre-created
|
||||
// Use a branch name that doesn't exist yet
|
||||
// Note: Worktrees are now created at execution time, not when adding to backlog
|
||||
const branchName = "feature/auto-create-worktree";
|
||||
const expectedWorktreePath = getWorktreePath(testRepo.path, branchName);
|
||||
|
||||
// Verify worktree does NOT exist before we create the feature
|
||||
expect(fs.existsSync(expectedWorktreePath)).toBe(false);
|
||||
// Verify branch does NOT exist before we create the feature
|
||||
const branchesBefore = await listBranches(testRepo.path);
|
||||
expect(branchesBefore).not.toContain(branchName);
|
||||
|
||||
// Click add feature button
|
||||
await clickAddFeature(page);
|
||||
@@ -802,17 +807,14 @@ test.describe("Worktree Integration Tests", () => {
|
||||
// Confirm
|
||||
await confirmAddFeature(page);
|
||||
|
||||
// Wait for the worktree to be created
|
||||
await page.waitForTimeout(2000);
|
||||
// Wait for feature to be saved
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Verify worktree was automatically created when feature was added
|
||||
expect(fs.existsSync(expectedWorktreePath)).toBe(true);
|
||||
// Verify branch was NOT created when adding feature (created at execution time)
|
||||
const branchesAfter = await listBranches(testRepo.path);
|
||||
expect(branchesAfter).not.toContain(branchName);
|
||||
|
||||
// Verify the branch was created
|
||||
const branches = await listBranches(testRepo.path);
|
||||
expect(branches).toContain(branchName);
|
||||
|
||||
// Verify feature was created with correct branch
|
||||
// Verify feature was created with correct branch name stored
|
||||
const featuresDir = path.join(testRepo.path, ".automaker", "features");
|
||||
const featureDirs = fs.readdirSync(featuresDir);
|
||||
expect(featureDirs.length).toBeGreaterThan(0);
|
||||
@@ -829,9 +831,15 @@ test.describe("Worktree Integration Tests", () => {
|
||||
|
||||
const featureFilePath = path.join(featuresDir, featureDir!, "feature.json");
|
||||
const featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8"));
|
||||
|
||||
// Verify branch name is stored
|
||||
expect(featureData.branchName).toBe(branchName);
|
||||
// Normalize paths for comparison (server returns forward slashes, path.join returns native)
|
||||
expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(expectedWorktreePath));
|
||||
|
||||
// Verify worktreePath is NOT set (worktrees are created at execution time)
|
||||
expect(featureData.worktreePath).toBeUndefined();
|
||||
|
||||
// Verify feature is in backlog status
|
||||
expect(featureData.status).toBe("backlog");
|
||||
});
|
||||
|
||||
test("should reset feature branch and worktree when worktree is deleted", async ({
|
||||
@@ -888,9 +896,11 @@ test.describe("Worktree Integration Tests", () => {
|
||||
|
||||
let featureFilePath = path.join(featuresDir, featureDir!, "feature.json");
|
||||
let featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8"));
|
||||
|
||||
// Verify feature was created with the branch name stored
|
||||
expect(featureData.branchName).toBe(branchName);
|
||||
// Normalize paths for comparison (server returns forward slashes, path.join returns native)
|
||||
expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(worktreePath));
|
||||
// Verify worktreePath is NOT set (worktrees are created at execution time, not when adding)
|
||||
expect(featureData.worktreePath).toBeUndefined();
|
||||
|
||||
// Delete the worktree via UI
|
||||
// Open the worktree actions menu
|
||||
@@ -913,10 +923,11 @@ test.describe("Worktree Integration Tests", () => {
|
||||
// Verify worktree is deleted
|
||||
expect(fs.existsSync(worktreePath)).toBe(false);
|
||||
|
||||
// Verify feature's branchName and worktreePath are reset to null
|
||||
// Verify feature's branchName is reset to null/undefined when worktree is deleted
|
||||
// (worktreePath was never stored, so it remains undefined)
|
||||
featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8"));
|
||||
expect(featureData.branchName).toBeNull();
|
||||
expect(featureData.worktreePath).toBeNull();
|
||||
expect(featureData.worktreePath).toBeUndefined();
|
||||
|
||||
// Verify the feature appears in the backlog when main is selected
|
||||
const mainButton = page.getByRole("button", { name: "main" }).first();
|
||||
@@ -942,8 +953,9 @@ test.describe("Worktree Integration Tests", () => {
|
||||
await otherWorktreeButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Unassigned features should still be visible in the backlog
|
||||
await expect(featureText).toBeVisible({ timeout: 5000 });
|
||||
// Unassigned features should NOT be visible on non-primary worktrees
|
||||
// They should only show on the primary (main) worktree
|
||||
await expect(featureText).not.toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test("should filter features by selected worktree", async ({ page }) => {
|
||||
@@ -1064,9 +1076,11 @@ test.describe("Worktree Integration Tests", () => {
|
||||
// Open add feature dialog
|
||||
await clickAddFeature(page);
|
||||
|
||||
// Verify the branch input button shows the selected worktree's branch
|
||||
const branchButton = page.locator('[data-testid="feature-branch-input"]');
|
||||
await expect(branchButton).toContainText(branchName, { timeout: 5000 });
|
||||
// Verify the branch selector shows the selected worktree's branch
|
||||
// When a worktree is selected, "Use current selected branch" should be selected
|
||||
// and the branch name should be shown in the label
|
||||
const currentBranchLabel = page.locator('label[for="feature-current"]');
|
||||
await expect(currentBranchLabel).toContainText(branchName, { timeout: 5000 });
|
||||
|
||||
// Close dialog
|
||||
await page.keyboard.press("Escape");
|
||||
@@ -2339,7 +2353,7 @@ test.describe("Worktree Integration Tests", () => {
|
||||
// Edit Feature with Branch Change
|
||||
// ==========================================================================
|
||||
|
||||
test("should create worktree when editing a feature and selecting a new branch", async ({
|
||||
test("should update branchName when editing a feature and selecting a new branch", async ({
|
||||
page,
|
||||
}) => {
|
||||
await setupProjectWithPath(page, testRepo.path);
|
||||
@@ -2385,7 +2399,7 @@ test.describe("Worktree Integration Tests", () => {
|
||||
const newBranchName = "feature/edited-branch";
|
||||
const expectedWorktreePath = getWorktreePath(testRepo.path, newBranchName);
|
||||
|
||||
// Verify worktree does NOT exist before editing
|
||||
// Verify worktree does NOT exist before editing (worktrees are created at execution time)
|
||||
expect(fs.existsSync(expectedWorktreePath)).toBe(false);
|
||||
|
||||
// Find and click the edit button on the feature card
|
||||
@@ -2400,8 +2414,12 @@ test.describe("Worktree Integration Tests", () => {
|
||||
const editDialog = page.locator('[data-testid="edit-feature-dialog"]');
|
||||
await expect(editDialog).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Select "Other branch" to enable the branch input
|
||||
const otherBranchRadio = page.locator('label[for="edit-feature-other"]');
|
||||
await otherBranchRadio.click();
|
||||
|
||||
// Find and click on the branch input to open the autocomplete
|
||||
const branchInput = page.locator('[data-testid="edit-feature-branch"]');
|
||||
const branchInput = page.locator('[data-testid="edit-feature-input"]');
|
||||
await branchInput.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
@@ -2417,21 +2435,22 @@ test.describe("Worktree Integration Tests", () => {
|
||||
const saveButton = page.locator('[data-testid="confirm-edit-feature"]');
|
||||
await saveButton.click();
|
||||
|
||||
// Wait for the dialog to close and worktree to be created
|
||||
// Wait for the dialog to close
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Verify worktree was automatically created
|
||||
expect(fs.existsSync(expectedWorktreePath)).toBe(true);
|
||||
// Verify worktree was NOT created during editing (worktrees are created at execution time)
|
||||
expect(fs.existsSync(expectedWorktreePath)).toBe(false);
|
||||
|
||||
// Verify the branch was created
|
||||
// Verify branch was NOT created (created at execution time)
|
||||
const branches = await listBranches(testRepo.path);
|
||||
expect(branches).toContain(newBranchName);
|
||||
expect(branches).not.toContain(newBranchName);
|
||||
|
||||
// Verify feature was updated with correct branch and worktreePath
|
||||
// Verify feature was updated with correct branchName only
|
||||
// Note: worktreePath is no longer stored - worktrees are created server-side at execution time
|
||||
featureData = JSON.parse(fs.readFileSync(featureFilePath, "utf-8"));
|
||||
expect(featureData.branchName).toBe(newBranchName);
|
||||
// Normalize paths for comparison (server returns forward slashes, path.join returns native)
|
||||
expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(expectedWorktreePath));
|
||||
// worktreePath should not exist in the feature data
|
||||
expect(featureData.worktreePath).toBeUndefined();
|
||||
});
|
||||
|
||||
test("should not create worktree when editing a feature and selecting main branch", async ({
|
||||
@@ -2494,7 +2513,7 @@ test.describe("Worktree Integration Tests", () => {
|
||||
await expect(editDialog).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Find and click on the branch input
|
||||
const branchInput = page.locator('[data-testid="edit-feature-branch"]');
|
||||
const branchInput = page.locator('[data-testid="edit-feature-input"]');
|
||||
await branchInput.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
@@ -2553,7 +2572,7 @@ test.describe("Worktree Integration Tests", () => {
|
||||
await expect(editDialog).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Change to the existing branch
|
||||
const branchInput = page.locator('[data-testid="edit-feature-branch"]');
|
||||
const branchInput = page.locator('[data-testid="edit-feature-input"]');
|
||||
await branchInput.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
@@ -2574,7 +2593,8 @@ test.describe("Worktree Integration Tests", () => {
|
||||
);
|
||||
expect(matchingWorktrees.length).toBe(1);
|
||||
|
||||
// Verify feature was updated with the correct worktreePath
|
||||
// Verify feature was updated with the correct branchName
|
||||
// Note: worktreePath is no longer stored - worktrees are created server-side at execution time
|
||||
const featuresDir = path.join(testRepo.path, ".automaker", "features");
|
||||
const featureDirs = fs.readdirSync(featuresDir);
|
||||
const featureDir = featureDirs.find((dir) => {
|
||||
@@ -2589,7 +2609,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);
|
||||
// Normalize paths for comparison (server returns forward slashes, path.join returns native)
|
||||
expect(path.normalize(featureData.worktreePath)).toBe(path.normalize(existingWorktreePath));
|
||||
// worktreePath should not exist in the feature data (worktrees are created at execution time)
|
||||
expect(featureData.worktreePath).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user