Skip to content

Comments

worktree-select#182

Merged
webdevcody merged 9 commits intomainfrom
worktree-select
Dec 20, 2025
Merged

worktree-select#182
webdevcody merged 9 commits intomainfrom
worktree-select

Conversation

@webdevcody
Copy link
Collaborator

@webdevcody webdevcody commented Dec 20, 2025

Changes from branch worktree-select

Summary by CodeRabbit

  • New Features

    • Auto-selects worktrees when creating features with new branches.
    • Automatically refreshes worktrees from disk every second.
    • Redesigned worktree panel UI that displays the active worktree separately from other branches with improved navigation.
  • Tests

    • Added test for auto-selecting worktrees after feature creation.
    • Improved editor persistence test reliability with content validation polling.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 20, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The PR implements automatic worktree selection when features are created with new branches. It refactors the worktree panel UI to split main and non-main worktrees, adds periodic background refresh, and enhances test reliability with improved synchronization and polling logic.

Changes

Cohort / File(s) Summary
Worktree Auto-Select Feature
apps/ui/src/components/views/board-view.tsx, apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
Adds onWorktreeAutoSelect callback to BoardView. The hook invokes this callback after creating a worktree during feature addition, allowing the UI to automatically select the new worktree with its path and branch.
Worktree Panel UI Refactoring
apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx, apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx
Splits worktree rendering into main (active) and non-main sections. Replaces ChevronDown/Up icons with PanelLeftOpen/Close. Converts PR badge from button to span with role="button". Adds 1-second periodic refresh via fetchWorktrees({ silent: true }).
Worktree Hook State Management
apps/ui/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts
Introduces ref-based tracking of current worktree across renders. Adds silent flag to fetchWorktrees to suppress loading indicator during background refreshes. Adds validation effect to handle invalid worktree selections and fallback to main branch.
Test Improvements
apps/ui/tests/spec-editor-persistence.spec.ts, apps/ui/tests/utils/views/spec-editor.ts, apps/ui/tests/worktree-integration.spec.ts
Replaces fixed delays with explicit content checks and polling logic for CodeMirror synchronization (up to 30 seconds). Adds new test for auto-select worktree after feature creation. Marks two flaky tests as skipped with explanations.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI (Board View)
    participant Hook as useBoardActions
    participant Store as Store
    participant Panel as Worktree Panel

    UI->>Hook: handleAddFeature(newBranch)
    Hook->>Store: Create feature with new branch
    Hook->>Hook: Create new worktree entry
    activate Hook
    Hook->>Panel: onWorktreeAutoSelect({ path, branch })
    deactivate Hook
    Panel->>Panel: Verify no duplicate worktree exists
    Panel->>Store: Append new worktree to store
    Panel->>Store: Select worktree (set current path/branch)
    Panel->>UI: Update UI with selected worktree
    UI->>UI: Auto-select worktree in panel
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Ref-based state management in use-worktrees.ts — verify correctness of currentWorktreeRef synchronization and validation effect dependencies
  • UI refactoring logic in worktree-panel.tsx — confirm main/non-main worktree split and periodic refresh behavior are correct
  • Callback wiring across board-view.tsx and use-board-actions.ts — ensure onWorktreeAutoSelect is properly threaded and invoked at the right time
  • Test polling logic in spec-editor-persistence.spec.ts — validate timeout and fallback behavior for CodeMirror content detection

Possibly related PRs

  • feat: add auto-generated titles for features #184: Modifies the same handleAddFeature hook and adds title/titleGenerating logic during feature addition, which interacts with the new onWorktreeAutoSelect callback flow.
  • Implement planning/speckits rebase #160: Updates use-board-actions.ts with planningMode/requirePlanApproval props alongside the onWorktreeAutoSelect addition, sharing the same hook refactoring context.
  • fixing worktree style #185: Modifies worktree-panel UI files (worktree-tab.tsx, worktree-panel.tsx) with additional styling and layout changes related to the same panel refactoring.

Poem

🐰 A worktree for each branch we grow,
Auto-select lets features flow,
Main and others neatly split,
Refresh in silence, bit by bit—
Fuzzy panels now take their bow! 🌿

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'worktree-select' is vague and generic, failing to clearly summarize the main changes in the pull request. Use a more descriptive title that captures the primary change, such as 'Auto-select worktree when creating feature with new branch' or 'Implement worktree auto-selection on feature creation'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch worktree-select

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @webdevcody, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request streamlines the workflow for creating new features by automatically selecting the corresponding Git worktree upon its creation. This enhancement improves user experience by immediately switching the development context. Additionally, it includes a critical fix to prevent race conditions in worktree state validation, ensuring more robust and reliable worktree management within the application.

Highlights

  • Automatic Worktree Selection: When a new feature is created, the associated Git worktree is now automatically selected in the UI, streamlining the workflow.
  • Enhanced Worktree State Management: Improved logic to add new worktrees to the application's store and set them as current, including checks to prevent duplicate entries.
  • Race Condition Prevention in Worktree Validation: A useRef and updated useEffect have been introduced in the useWorktrees hook to prevent race conditions during worktree validation and selection, ensuring more robust state management.
  • New Integration Test: A new integration test has been added to verify that the auto-selection of worktrees functions correctly after creating a feature with a new branch.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a helpful feature to auto-select a worktree when a new feature is created for it. It also includes a good fix for a race condition in the worktree validation logic. My review focuses on improving the code structure by moving state logic out of the view component and enhancing the quality and reliability of the new integration test.

await confirmAddFeature(page);

// Wait for feature to be saved and worktree to be created
await page.waitForTimeout(2000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of page.waitForTimeout(2000) can lead to flaky tests. It's a fixed wait that might be too short on a slow machine or too long on a fast one, slowing down the test suite. It's better to rely on Playwright's auto-waiting capabilities by waiting for a specific condition to be met. In this case, you can directly wait for the worktree button to become visible and then for it to have the 'active' state.

I suggest removing this line. The subsequent expect(worktreeButton).toBeVisible(...) and expect(worktreeButton).toHaveAttribute(...) calls with their timeouts are sufficient and more reliable.

Comment on lines +416 to +444
onWorktreeAutoSelect: (newWorktree) => {
if (!currentProject) return;
// Check if worktree already exists in the store (by branch name)
const currentWorktrees = getWorktrees(currentProject.path);
const existingWorktree = currentWorktrees.find(
(w) => w.branch === newWorktree.branch
);

// Only add if it doesn't already exist (to avoid duplicates)
if (!existingWorktree) {
const newWorktreeInfo = {
path: newWorktree.path,
branch: newWorktree.branch,
isMain: false,
isCurrent: false,
hasWorktree: true,
};
setWorktrees(currentProject.path, [
...currentWorktrees,
newWorktreeInfo,
]);
}
// Select the worktree (whether it existed or was just added)
setCurrentWorktree(
currentProject.path,
newWorktree.path,
newWorktree.branch
);
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for onWorktreeAutoSelect is implemented directly within the BoardView component. This business logic, which involves reading from and writing to the application state, would be better placed within the useAppStore Zustand store as a dedicated action. This would improve separation of concerns, make the BoardView component cleaner, and centralize state management logic.

I suggest creating a new action in app-store.ts, for example autoSelectWorktree, and calling it from use-board-actions.ts. This would also remove the need to pass onWorktreeAutoSelect as a prop.

Comment on lines 892 to 894
// Verify the feature is visible in the backlog (which means the worktree is selected)
const featureText = page.getByText("Feature with auto-select worktree");
await expect(featureText).toBeVisible({ timeout: 5000 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This verification block is redundant. The same check (expect(featureText).toBeVisible(...)) is already performed within the .catch() block of the preceding assertion on lines 885-890. If the primary assertion on the button's data-state fails, the fallback in the catch block runs. In either case, this final check is duplicative. To keep the test DRY and focused, this block should be removed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/app/src/components/views/board-view/hooks/use-board-actions.ts (1)

119-141: Consider handling the case when result.success is true but result.worktree is missing.

The current logic has three possible outcomes:

  1. result.success && result.worktree → auto-select and refresh (lines 120-131)
  2. !result.success → show error (lines 132-140)
  3. result.success && !result.worktree → no handling (falls through silently)

Case 3 seems unexpected. If the API returns success but no worktree object, should this be logged or treated as an error? Consider adding an else clause to handle or at least log this edge case.

🔎 Proposed fix to handle all cases
            if (result.success && result.worktree) {
              console.log(
                `[Board] Worktree for branch "${finalBranchName}" ${
                  result.worktree?.isNew ? "created" : "already exists"
                }`
              );
              // Auto-select the worktree when creating a feature for it
              onWorktreeAutoSelect?.({
                path: result.worktree.path,
                branch: result.worktree.branch,
              });
              // Refresh worktree list in UI
              onWorktreeCreated?.();
            } else if (!result.success) {
              console.error(
                `[Board] Failed to create worktree for branch "${finalBranchName}":`,
                result.error
              );
              toast.error("Failed to create worktree", {
                description: result.error || "An error occurred",
              });
+           } else {
+             // result.success is true but result.worktree is missing - unexpected
+             console.warn(
+               `[Board] Worktree creation succeeded but no worktree object returned for branch "${finalBranchName}"`
+             );
            }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cb085f and 89c53ac.

📒 Files selected for processing (4)
  • apps/app/src/components/views/board-view.tsx (1 hunks)
  • apps/app/src/components/views/board-view/hooks/use-board-actions.ts (4 hunks)
  • apps/app/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (2 hunks)
  • apps/app/tests/worktree-integration.spec.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/app/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (1)
apps/app/src/lib/utils.ts (1)
  • pathsEqual (51-54)
apps/app/tests/worktree-integration.spec.ts (4)
apps/app/tests/utils/git/worktree.ts (3)
  • setupProjectWithPath (309-353)
  • waitForBoardView (462-464)
  • listBranches (194-200)
apps/app/tests/utils/core/waiting.ts (1)
  • waitForNetworkIdle (7-9)
apps/app/tests/utils/api/client.ts (1)
  • listBranches (179-189)
apps/app/tests/utils/views/board.ts (3)
  • clickAddFeature (121-126)
  • fillAddFeatureDialog (131-180)
  • confirmAddFeature (185-192)
🔇 Additional comments (5)
apps/app/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (2)

3-3: LGTM! Clean ref pattern to avoid race condition.

The useRef pattern correctly captures the current worktree value, allowing the validation effect to access the latest selection without depending on it directly in the dependency array. This prevents the validation effect from running on every selection change, which could cause a race condition with stale worktrees data.

Also applies to: 62-67


69-88: Well-designed fix for the race condition.

The validation effect now only triggers when the worktrees list changes, not when the selection changes. By using the ref to access the current selection, this prevents a race condition where a selection change could trigger validation before the worktrees list is updated, causing an incorrect reset to main.

The logic correctly:

  1. Checks if the current selection still exists in the updated worktrees list
  2. Resets to main branch only if the current worktree is invalid or no longer exists
  3. Excludes currentWorktree from dependencies to avoid the race condition
apps/app/src/components/views/board-view.tsx (1)

416-444: LGTM! Auto-selection logic is correctly implemented.

The callback properly:

  1. Checks for existing worktrees by branch to avoid duplicates
  2. Adds the new worktree to the store with correct structure
  3. Selects the worktree regardless of whether it was just added or already existed

The newWorktreeInfo structure correctly sets isMain: false, isCurrent: false, and hasWorktree: true for the newly created/found worktree.

apps/app/src/components/views/board-view/hooks/use-board-actions.ts (2)

44-44: LGTM! Clean type definition.

The optional onWorktreeAutoSelect prop is properly typed with the correct structure ({ path: string; branch: string }), and it's correctly destructured in the function signature.

Also applies to: 72-72


161-161: LGTM! Dependency array is complete.

The dependency array correctly includes onWorktreeAutoSelect along with all other dependencies used in the callback.

- Simplified the formatting of dropdown open change handlers for better readability.
- Updated the label from "Branch:" to "Worktrees:" for clarity.
- Enhanced conditional checks for removed worktrees to improve code structure.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/ui/src/components/views/board-view.tsx (1)

421-449: Duplicated worktree creation logic — consider extracting to a shared helper or store action.

This onWorktreeAutoSelect callback duplicates the logic in CreateWorktreeDialog.onCreated (lines 1161-1186). Both:

  1. Check for existing worktrees by branch
  2. Create a newWorktreeInfo object with the same shape
  3. Append to worktrees via setWorktrees
  4. Call setCurrentWorktree

As noted in a previous review, consolidating this into a dedicated Zustand store action (e.g., addAndSelectWorktree) would eliminate duplication, centralize state management, and simplify the component.

🧹 Nitpick comments (2)
apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (1)

154-189: Consider using a native <button> element instead of <span role="button">.

While the current implementation with role="button", tabIndex={0}, and keyboard handling is functionally correct, a native <button> element provides these accessibility features by default and handles additional edge cases (e.g., form submission context, disabled state behavior). The styling can still be customized with utility classes.

If there's a specific reason for avoiding a nested button (e.g., HTML validation concerns with button-inside-button), you could extract the badge outside the parent button's DOM hierarchy or use CSS pointer-events to manage the interaction.

apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (1)

185-218: Note: handleUpdateFeature doesn't auto-select newly created worktrees.

Unlike handleAddFeature, this function creates a worktree for the branch but doesn't call onWorktreeAutoSelect. This asymmetry appears intentional (editing shouldn't change the user's current view), but worth confirming this is the desired UX.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89c53ac and dcf19fb.

📒 Files selected for processing (6)
  • apps/app/next-env.d.ts (1 hunks)
  • apps/ui/src/components/views/board-view.tsx (1 hunks)
  • apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (4 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (2 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (2 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/app/next-env.d.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (3)
apps/ui/src/components/views/board-view/worktree-panel/types.ts (1)
  • WorktreeInfo (9-18)
apps/ui/src/types/electron.d.ts (1)
  • WorktreeInfo (578-583)
apps/ui/src/lib/electron.ts (1)
  • WorktreeInfo (52-52)
🔇 Additional comments (3)
apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (1)

90-103: LGTM!

The formatting improvements and label update from "Branch:" to "Worktrees:" are clean cosmetic changes with no functional impact.

Also applies to: 112-112, 141-146, 180-184

apps/ui/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (1)

61-87: Good use of ref to decouple validation from selection changes.

The currentWorktreeRef pattern correctly prevents the validation effect from re-running when the user selects a worktree, avoiding the race condition where stale worktrees state could incorrectly reset the selection.

One subtle note: when worktrees updates, the validation effect reads the previous currentWorktree value from the ref (since the ref-sync effect runs on currentWorktree changes, not worktrees changes). This appears intentional and correct for this use case — you validate against the previously established selection, not a concurrent selection change.

apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (1)

119-132: LGTM — auto-select correctly integrated for new features.

The null check on result.worktree before accessing its properties is correct. The optional chaining on onWorktreeAutoSelect?.() safely handles cases where the callback isn't provided.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/ui/src/components/views/board-view.tsx (1)

421-449: Acknowledge the existing review feedback regarding state management location.

A previous review suggested moving this onWorktreeAutoSelect logic into the Zustand store as a dedicated action rather than implementing it directly in the component. This would improve separation of concerns and centralize state management.

The current implementation is functional, but consider refactoring this into app-store.ts as an autoSelectWorktree action in a future iteration.

Based on past review comments suggesting this logic belongs in the Zustand store rather than the component.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcf19fb and 1a4e6ff.

📒 Files selected for processing (5)
  • apps/ui/src/components/views/board-view.tsx (1 hunks)
  • apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (7 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (2 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (4 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (2)
apps/ui/src/components/views/board-view/worktree-panel/types.ts (1)
  • WorktreeInfo (9-18)
apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (1)
  • WorktreeTab (55-337)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (5)
apps/ui/src/components/views/board-view/worktree-panel/hooks/use-worktrees.ts (2)

66-92: Well-designed solution to prevent race conditions.

The ref-based approach (currentWorktreeRef) effectively prevents the validation effect from racing with selection changes. By only running validation when the worktrees list changes (not on selection changes), you avoid the issue where stale worktree data causes the selection to be reset prematurely.

This is a clean pattern for handling async state synchronization issues.


23-50: Silent fetch option improves UX for background refreshes.

The optional silent flag allows periodic background refreshes without showing loading indicators, which is appropriate for the 1-second polling interval introduced in worktree-panel.tsx. This prevents unnecessary UI flickering.

apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (2)

120-133: Auto-select flow correctly implemented.

The onWorktreeAutoSelect callback is invoked at the right point in the flow—after successful worktree creation and before the UI refresh. This ensures the newly created worktree is automatically selected, providing a seamless user experience.

The conditional logic properly checks for both result.success and result.worktree before invoking the callback.


199-209: Dependency array correctly updated.

The onWorktreeAutoSelect callback has been properly included in the handleAddFeature dependency array, ensuring the memoized function stays current when the callback reference changes.

apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (1)

154-340: Well-structured UI refactoring for main and non-main worktrees.

The separation of main worktree and non-main worktrees into distinct sections improves clarity and user experience. The main worktree is always visible under "Branch:", while additional worktrees appear under "Worktrees:" when enabled.

The refactored dropdown handlers using currying are clean and maintainable.

Comment on lines +105 to +117
// Periodic interval check (1 second) to detect branch changes on disk
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
fetchWorktrees({ silent: true });
}, 1000);

return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [fetchWorktrees]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Consider increasing the polling interval to reduce overhead.

A 1-second polling interval may be too aggressive, especially when the panel is expanded and users are actively working. This creates 60 API calls per minute to check for branch changes on disk.

Consider:

  • Increasing the interval to 5-10 seconds for a better balance between responsiveness and resource usage
  • Implementing a smart polling strategy that polls more frequently when changes are detected
  • Using file system watchers (if available in Electron) instead of polling
🔎 Suggested interval adjustment
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      fetchWorktrees({ silent: true });
-   }, 1000);
+   }, 5000); // Poll every 5 seconds instead of 1 second
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Periodic interval check (1 second) to detect branch changes on disk
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
fetchWorktrees({ silent: true });
}, 1000);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [fetchWorktrees]);
// Periodic interval check (1 second) to detect branch changes on disk
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
fetchWorktrees({ silent: true });
}, 5000); // Poll every 5 seconds instead of 1 second
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [fetchWorktrees]);

- Updated spec editor persistence test to wait for loading state and content updates.
- Improved worktree integration test to ensure worktree button visibility and selected state after creation.
- Refactored getEditorContent function to ensure CodeMirror content is fully loaded before retrieval.
- Increased wait times in spec editor persistence test to ensure content is fully loaded and saved.
- Added verification of content before saving in the spec editor test.
- Marked worktree panel visibility test as skipped due to flakiness caused by component rendering behavior.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/ui/tests/spec-editor-persistence.spec.ts (2)

66-70: Consider removing redundant wait after save.

The clickSaveButton utility already waits up to 5 seconds for the button text to change to "Saved", indicating the save operation is complete. The additional 1000ms wait at line 70 is likely redundant and slows down the test unnecessarily.

🔎 Suggested simplification
 // Step 8: Click the save button and wait for save to complete
 await clickSaveButton(page);
-
-// Additional wait to ensure save operation completes and file is written
-await page.waitForTimeout(1000);

96-111: Consider removing redundant wait before content polling.

The content polling logic (lines 99-111) already waits up to 15 seconds for the content to match, checking continuously. The fixed 1000ms wait at line 97 is likely redundant—if CodeMirror needs time to update, the polling will handle it.

🔎 Suggested simplification
 );
-
-// Additional wait for CodeMirror to update after loading
-await page.waitForTimeout(1000);

 // Wait for CodeMirror content to update with the loaded spec
-// CodeMirror might need a moment to update its DOM after the value prop changes
 await page.waitForFunction(
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb87c8b and f1eba5e.

📒 Files selected for processing (2)
  • apps/ui/tests/spec-editor-persistence.spec.ts (2 hunks)
  • apps/ui/tests/worktree-integration.spec.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/ui/tests/worktree-integration.spec.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/ui/tests/spec-editor-persistence.spec.ts (1)
apps/ui/tests/utils/views/spec-editor.ts (3)
  • setEditorContent (79-105)
  • getEditorContent (65-74)
  • clickSaveButton (110-122)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (3)
apps/ui/tests/spec-editor-persistence.spec.ts (3)

57-57: Increased wait addresses editor initialization timing.

The increased timeout from 500ms to 1000ms may help with CodeMirror initialization, though fixed timeouts are generally less reliable than explicit state checks. If this addresses real flakiness, it's acceptable.


62-64: Good addition: pre-save content verification.

Verifying the editor content before saving ensures setEditorContent succeeded and makes the test more robust by catching issues earlier in the flow.


87-94: Good addition: explicit loading state check.

Waiting for the loading indicator to disappear is a robust approach that ensures the spec has finished loading before proceeding.

- Removed unnecessary wait times to streamline the test flow.
- Implemented a polling mechanism to verify content loading after page reload, enhancing test robustness.
- Updated the worktree integration test to skip unreliable scenarios related to component rendering.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/ui/tests/spec-editor-persistence.spec.ts (1)

81-117: Simplify using Playwright's built-in retry mechanisms.

The custom polling loop with waitForTimeout adds complexity and uses a Playwright anti-pattern. The fallback logic suggests the polling approach may not be fully reliable. Consider these simpler, more idiomatic alternatives:

Option 1 (recommended): Use Playwright's expect with built-in retry

// Wait for CodeMirror content to update with the loaded spec
await expect(page.locator('[data-testid="spec-editor"] .cm-content'))
  .toHaveText("hello world", { timeout: 30000 });

Option 2: Use only the waitForFunction approach

// Wait for CodeMirror content to update with the loaded spec
await page.waitForFunction(
  (expectedContent) => {
    const contentElement = document.querySelector('[data-testid="spec-editor"] .cm-content');
    if (!contentElement) return false;
    const text = (contentElement.textContent || "").trim();
    return text === expectedContent;
  },
  "hello world",
  { timeout: 30000 }
);

Both alternatives eliminate the manual polling loop and waitForTimeout, which is discouraged in Playwright documentation.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1eba5e and 46210c5.

📒 Files selected for processing (2)
  • apps/ui/tests/spec-editor-persistence.spec.ts (2 hunks)
  • apps/ui/tests/worktree-integration.spec.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/ui/tests/worktree-integration.spec.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/ui/tests/spec-editor-persistence.spec.ts (1)
apps/ui/tests/utils/views/spec-editor.ts (1)
  • getEditorContent (65-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (1)
apps/ui/tests/spec-editor-persistence.spec.ts (1)

59-61: Good addition: Pre-save content verification.

This verification step ensures the editor content was successfully set before attempting to save, which improves test reliability and makes failures easier to diagnose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant