Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions PolyPilot.Tests/RepoPickerConsistencyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System.Text.RegularExpressions;

namespace PolyPilot.Tests;

/// <summary>
/// Regression tests for the repo picker consistency bug:
/// "New Session" (CreateSessionForm.razor) used a &lt;select&gt; dropdown for repositories,
/// while "New Multi-Agent" (SessionSidebar.razor) used a list of clickable buttons.
/// Fix: both flows now use the same &lt;select&gt; dropdown pattern with the "ns-repo-select" CSS class,
/// and auto-advance to step 2 when there's only one repository.
/// </summary>
public class RepoPickerConsistencyTests
{
private static string GetRepoRoot()
{
var dir = AppContext.BaseDirectory;
while (dir != null && !File.Exists(Path.Combine(dir, "PolyPilot.slnx")))
dir = Directory.GetParent(dir)?.FullName;
return dir ?? throw new DirectoryNotFoundException("Could not find repo root (PolyPilot.slnx not found)");
}

private static string CreateSessionFormPath =>
Path.Combine(GetRepoRoot(), "PolyPilot", "Components", "Layout", "CreateSessionForm.razor");

private static string SessionSidebarPath =>
Path.Combine(GetRepoRoot(), "PolyPilot", "Components", "Layout", "SessionSidebar.razor");

// ── Both forms use <select> for repo picking ────────────────────────────

[Fact]
public void CreateSessionForm_UsesSelectDropdownForRepos()
{
var content = File.ReadAllText(CreateSessionFormPath);
// The "new session" form uses <select class="ns-repo-select"> for repo picker
Assert.Contains("ns-repo-select", content);
Assert.Matches(new Regex(@"<select\s[^>]*class=""ns-repo-select"""), content);
}

[Fact]
public void SessionSidebar_MultiAgent_UsesSelectDropdownForRepos()
{
var content = File.ReadAllText(SessionSidebarPath);
// The multi-agent flow should also use <select class="ns-repo-select"> (not button list)
Assert.Contains("ns-repo-select", content);
// Verify the select is within the multi-agent repo picker section
Assert.Contains("OnMultiAgentRepoChanged", content);
Assert.Matches(new Regex(@"<select\s[^>]*class=""ns-repo-select""[^>]*@onchange=""OnMultiAgentRepoChanged"""), content);
}

[Fact]
public void SessionSidebar_MultiAgent_DoesNotUseButtonListForRepos()
{
var content = File.ReadAllText(SessionSidebarPath);
// The old pattern used <button class="worktree-item"> for each repo in the multi-agent picker.
// After the fix, the multi-agent step-1 section should NOT have worktree-item buttons for repos.
// Extract the step 1 section (between "Step 1" comment and the next else if)
var step1Match = Regex.Match(content, @"Step 1:.*?(?=else if \(pendingMultiAgentRepo)", RegexOptions.Singleline);
if (step1Match.Success)
{
var step1Content = step1Match.Value;
Assert.DoesNotContain("worktree-item", step1Content);
}
}

// ── Single-repo auto-advance ────────────────────────────────────────────

[Fact]
public void CreateSessionForm_ShowsLabelForSingleRepo()
{
var content = File.ReadAllText(CreateSessionFormPath);
// When there's only 1 repo, CreateSessionForm shows a label instead of a dropdown
Assert.Contains("ns-repo-label", content);
}

[Fact]
public void SessionSidebar_MultiAgent_ShowsLabelForSingleRepo()
{
var content = File.ReadAllText(SessionSidebarPath);
// When there's only 1 repo, the multi-agent picker should also show a label
Assert.Contains("ns-repo-label", content);
}

[Fact]
public void SessionSidebar_MultiAgent_AutoAdvancesForSingleRepo()
{
var content = File.ReadAllText(SessionSidebarPath);
// StartAddMultiAgentGroup should auto-advance when Repositories.Count == 1
Assert.Contains("Repositories.Count == 1", content);
Assert.Contains("SelectRepoForGroup", content);
}

// ── Dropdown has placeholder option ─────────────────────────────────────

[Fact]
public void SessionSidebar_MultiAgent_DropdownHasPlaceholder()
{
var content = File.ReadAllText(SessionSidebarPath);
// The dropdown should have a placeholder "Pick a repo" option
Assert.Contains("Pick a repo", content);
}

// ── Handler exists for dropdown change event ────────────────────────────

[Fact]
public void SessionSidebar_HasOnMultiAgentRepoChangedHandler()
{
var content = File.ReadAllText(SessionSidebarPath);
// The handler should look up the repo by ID and call SelectRepoForGroup
Assert.Matches(new Regex(@"void\s+OnMultiAgentRepoChanged\s*\("), content);
}
}
34 changes: 26 additions & 8 deletions PolyPilot/Components/Layout/SessionSidebar.razor
Original file line number Diff line number Diff line change
Expand Up @@ -240,21 +240,27 @@ else
}
else if (isAddingMultiAgentGroup && pendingMultiAgentRepo == null)
{
@* Step 1: Pick a repository *@
@* Step 1: Pick a repository — uses dropdown to match CreateSessionForm *@
<div class="worktree-picker" @onclick:stopPropagation="true">
<div class="worktree-picker-header">
<span>Select repository for team:</span>
<button class="worktree-cancel-btn" @onclick="CancelMultiAgentCreation">✕</button>
</div>
@foreach (var repo in RepoManager.Repositories)
@if (RepoManager.Repositories.Count > 1)
{
var r = repo;
<button class="worktree-item" @onclick="() => SelectRepoForGroup(r)" title="@r.Url">
<span class="worktree-branch">@r.Name</span>
<span class="worktree-path">@r.Url</span>
</button>
<select class="ns-repo-select" style="margin: 4px 8px;" @onchange="OnMultiAgentRepoChanged">
<option value="" selected>— Pick a repo —</option>
@foreach (var repo in RepoManager.Repositories)
{
<option value="@repo.Id">@repo.Name</option>
}
</select>
}
@if (!RepoManager.Repositories.Any())
else if (RepoManager.Repositories.Count == 1)
{
<div class="ns-repo-label" style="margin: 4px 8px;">📦 @RepoManager.Repositories[0].Name</div>
}
else
{
<div class="worktree-empty">No repositories available. Add a repository first.</div>
}
Expand Down Expand Up @@ -1970,6 +1976,10 @@ else
isAddingGroup = false;
isAddingMultiAgentGroup = true;
pendingMultiAgentRepo = null;

// Auto-advance when there's exactly 1 repo (matches CreateSessionForm behavior)
if (RepoManager.Repositories.Count == 1)
SelectRepoForGroup(RepoManager.Repositories[0]);
}

private void CancelMultiAgentCreation()
Expand All @@ -1978,6 +1988,14 @@ else
pendingMultiAgentRepo = null;
}

private void OnMultiAgentRepoChanged(ChangeEventArgs e)
{
var repoId = e.Value?.ToString();
if (string.IsNullOrEmpty(repoId)) return;
var repo = RepoManager.Repositories.FirstOrDefault(r => r.Id == repoId);
if (repo != null) SelectRepoForGroup(repo);
}

private void SelectRepoForGroup(RepositoryInfo repo)
{
// Repo selected — advance to step 2 (presets + custom name)
Expand Down