pi-agent: Fix final integrated review

This commit is contained in:
proxyctl coordinator
2026-07-18 02:37:54 +08:00
parent ed8b527f1f
commit 652d7eba2b
18 changed files with 566 additions and 393 deletions
+82 -3
View File
@@ -5,6 +5,7 @@ import (
"strings"
"testing"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"proxyctl/internal/app"
@@ -50,6 +51,35 @@ func applyOperationCommand(t *testing.T, model Model, command tea.Cmd) (Model, t
return updated.(Model), next
}
func TestCompleteModelUsesAnimatedBubblesSpinnerOnlyWhileOperationRuns(t *testing.T) {
updates := make(chan app.OperationUpdate)
module := &interactiveScriptModule{snapshot: operationSnapshot(), streams: []chan app.OperationUpdate{updates}}
model := resizedModel(t, module, themeModeNoColor, 120, 36)
updated, command := model.Update(tea.KeyMsg{Type: tea.KeySpace})
model = updated.(Model)
if command == nil || !strings.Contains(model.View(), "| Applying") {
t.Fatalf("operation did not start the Bubbles spinner:\n%s", model.View())
}
updated, next := model.Update(spinner.TickMsg{ID: model.operation.spinner.ID()})
model = updated.(Model)
if next == nil || !strings.Contains(model.View(), "/ Applying") {
t.Fatalf("spinner tick did not animate the in-row Applying marker:\n%s", model.View())
}
terminal := app.SucceededOperationUpdate(module.snapshot,
app.OperationStatus{Summary: "Shell Target is now Enabled", TargetID: "shell"},
[]app.TargetProgress{{TargetID: "shell", Phase: app.TargetProgressSucceeded}})
updated, _ = model.Update(operationProgress{update: terminal, updates: updates})
model = updated.(Model)
terminalView := model.View()
updated, stale := model.Update(spinner.TickMsg{ID: model.operation.spinner.ID()})
model = updated.(Model)
if stale != nil || model.View() != terminalView || strings.Contains(model.View(), "Applying") {
t.Fatalf("spinner tick changed terminal operation state:\n%s", model.View())
}
}
func TestCompleteModelKeepsDashboardAndHelpBrowsableWhileMutationIsSerialized(t *testing.T) {
updates := make(chan app.OperationUpdate, 2)
module := &interactiveScriptModule{snapshot: operationSnapshot(), streams: []chan app.OperationUpdate{updates}}
@@ -129,7 +159,32 @@ func TestCompleteModelPreservesExpandableCurrentErrorAndFocusesFirstFailedTarget
}
}
func TestCompleteModelClearsCurrentErrorForDirectlyRelatedSuccessfulDetection(t *testing.T) {
func TestCompleteModelReadOnlyRefreshDoesNotClearTargetMutationErrorForSameTarget(t *testing.T) {
failure := make(chan app.OperationUpdate, 1)
refresh := make(chan app.OperationUpdate, 1)
module := &interactiveScriptModule{snapshot: operationSnapshot(), streams: []chan app.OperationUpdate{failure, refresh}}
model := resizedModel(t, module, themeModeNoColor, 120, 36)
updated, command := model.Update(tea.KeyMsg{Type: tea.KeySpace})
model = updated.(Model)
failure <- app.FailedOperationUpdate(module.snapshot,
app.OperationStatus{Summary: "Shell Target update failed", TargetID: "shell"}, nil, "shell", errors.New("permission denied"))
close(failure)
model, _ = applyOperationCommand(t, model, command)
updated, command = model.Update(keyMessage("r"))
model = updated.(Model)
refresh <- app.SucceededOperationUpdate(module.snapshot,
app.OperationStatus{Summary: "Shell Target check completed", TargetID: "shell"},
[]app.TargetProgress{{TargetID: "shell", Phase: app.TargetProgressSucceeded}})
close(refresh)
model, _ = applyOperationCommand(t, model, command)
if !strings.Contains(model.View(), "Current error: Shell Target update failed") {
t.Fatalf("read-only Refresh Targets cleared an unresolved mutation error:\n%s", model.View())
}
}
func TestCompleteModelRelatedTargetMutationClearsErrorForSameTarget(t *testing.T) {
failure := make(chan app.OperationUpdate, 1)
resolution := make(chan app.OperationUpdate, 1)
module := &interactiveScriptModule{snapshot: operationSnapshot(), streams: []chan app.OperationUpdate{failure, resolution}}
@@ -145,12 +200,36 @@ func TestCompleteModelClearsCurrentErrorForDirectlyRelatedSuccessfulDetection(t
updated, command = model.Update(tea.KeyMsg{Type: tea.KeySpace})
model = updated.(Model)
resolution <- app.SucceededOperationUpdate(module.snapshot,
app.OperationStatus{Summary: "Shell Target check completed", TargetID: "shell"},
app.OperationStatus{Summary: "Shell Target is now Enabled", TargetID: "shell"},
[]app.TargetProgress{{TargetID: "shell", Phase: app.TargetProgressSucceeded}})
close(resolution)
model, _ = applyOperationCommand(t, model, command)
if strings.Contains(model.View(), "Current error:") {
t.Fatalf("explicit related resolution did not clear the current error:\n%s", model.View())
t.Fatalf("explicit related Target resolution did not clear the current error:\n%s", model.View())
}
}
func TestCompleteModelSuccessfulRefreshClearsOnlyRefreshError(t *testing.T) {
failure := make(chan app.OperationUpdate, 1)
resolution := make(chan app.OperationUpdate, 1)
module := &interactiveScriptModule{snapshot: operationSnapshot(), streams: []chan app.OperationUpdate{failure, resolution}}
model := resizedModel(t, module, themeModeNoColor, 120, 36)
updated, command := model.Update(keyMessage("r"))
model = updated.(Model)
failure <- app.FailedOperationUpdate(module.snapshot,
app.OperationStatus{Summary: "Some Target checks failed", TargetID: "shell"}, nil, "shell", errors.New("inspection failed"))
close(failure)
model, _ = applyOperationCommand(t, model, command)
updated, command = model.Update(keyMessage("r"))
model = updated.(Model)
resolution <- app.SucceededOperationUpdate(module.snapshot,
app.OperationStatus{Summary: "Target availability and state checks completed"}, nil)
close(resolution)
model, _ = applyOperationCommand(t, model, command)
if strings.Contains(model.View(), "Current error:") {
t.Fatalf("successful Refresh Targets did not clear its own error:\n%s", model.View())
}
}