Files
proxy/internal/tui/dashboard_test.go
T
2026-08-30 15:49:04 +08:00

122 lines
5.8 KiB
Go

package tui
import (
"fmt"
"strings"
"testing"
"proxyctl/internal/app"
"proxyctl/internal/target"
)
func TestCompleteModelWideOperationsConsoleShowsStableAvailableTargetDashboard(t *testing.T) {
module := &recordingModule{snapshot: app.Snapshot{
ActiveProfile: "office",
Targets: []app.TargetSnapshot{
{ID: "shell", Description: target.Description{Name: "Shell", Summary: "Shell summary", Details: "Shell details"}, Available: true, State: target.Enabled, Evidence: "matches Active Profile"},
{ID: "apt", Description: target.Description{Name: "APT"}, Available: false, AvailabilityEvidence: "apt-config was not detected"},
{ID: "docker-client", Description: target.Description{Name: "Docker client"}, Available: true, State: target.External, Evidence: "existing settings"},
{ID: "gnome", Description: target.Description{Name: "GNOME"}, Available: true, State: target.Disabled, Evidence: "proxy mode is none"},
{ID: "docker-daemon", Description: target.Description{Name: "Docker daemon"}, Available: true, State: target.Drifted, Evidence: "managed values differ"},
},
}}
view := resizedModel(t, module, themeModeNoColor, 120, 36).View()
assertUsableFrame(t, view, 120, 36,
"proxyctl", "Profile: office",
"> ● Enabled", "Shell", "matches Active Profile",
)
if strings.Contains(view, "APT") || strings.Contains(view, "apt-config was not detected") {
t.Fatalf("default dashboard included an unavailable Target:\n%s", view)
}
if !sameLine(view, "Targets", "Target details") {
t.Fatalf("wide dashboard did not compose list and details side by side:\n%s", view)
}
if !(strings.Index(view, "Shell") < strings.Index(view, "Docker client") && strings.Index(view, "Docker client") < strings.Index(view, "GNOME") && strings.Index(view, "GNOME") < strings.Index(view, "Docker daemon")) {
t.Fatalf("available Target product order changed:\n%s", view)
}
}
func TestCompleteModelFailedProgressSupplementsTruthfulTargetState(t *testing.T) {
for _, state := range []target.State{target.Enabled, target.Disabled, target.External, target.Drifted} {
t.Run(string(state), func(t *testing.T) {
module := &recordingModule{snapshot: app.Snapshot{Targets: []app.TargetSnapshot{{
ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: state,
}}}}
model := resizedModel(t, module, themeModeNoColor, 120, 36)
model.operation.progress["shell"] = app.TargetProgressFailed
view := model.View()
wantState := targetStateLabel(state)
if !strings.Contains(view, "> "+wantState+" ! Failed Shell") {
t.Fatalf("failed progress replaced truthful %s state instead of supplementing it:\n%s", state, view)
}
})
}
}
func TestCompleteModelDashboardRevealsUnavailableEvidenceAndStructuredDetails(t *testing.T) {
module := &recordingModule{snapshot: app.Snapshot{Targets: []app.TargetSnapshot{
{ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: target.Disabled, Evidence: "fragment absent"},
{ID: "apt", Description: target.Description{
Name: "APT", Summary: "Persistent package proxy.", Details: "Longer APT explanation.",
Scope: "package operations across privilege boundaries", Permissions: "pre-existing root write authority",
Ownership: "isolated overlay; disabling reveals the previous configuration", RestartRisk: "none",
}, Available: false, AvailabilityEvidence: "apt-config was not detected"},
{ID: "docker", Description: target.Description{Name: "Docker daemon"}, Available: true, State: target.Enabled, Evidence: "managed values match"},
}}}
model := resizedModel(t, module, themeModeNoColor, 120, 36)
model = updateKey(model, "u")
model = updateKey(model, "down")
view := model.View()
assertUsableFrame(t, view, 120, 36,
"> ○ Unavailable APT", "○ Unavailable", "apt-config was not detected",
"Persistent package proxy.", "u: Hide unavailable",
)
if !(strings.Index(view, "Shell") < strings.Index(view, "APT") && strings.Index(view, "APT") < strings.Index(view, "Docker daemon")) {
t.Fatalf("revealing unavailable Targets changed product order:\n%s", view)
}
if strings.Contains(view, "Space: toggle") {
t.Fatalf("unavailable Target exposed a mutation action:\n%s", view)
}
}
func TestCompleteModelNarrowDashboardFocusAndIndependentScrollingRetainTargetIdentity(t *testing.T) {
targets := make([]app.TargetSnapshot, 28)
for i := range targets {
targets[i] = app.TargetSnapshot{
ID: fmt.Sprintf("target-%02d", i), Description: target.Description{Name: fmt.Sprintf("Product Target %02d", i)},
Available: true, State: target.Disabled, Evidence: fmt.Sprintf("evidence-%02d", i),
}
}
targets[22].Description.Summary = "Selected identity summary"
targets[22].Evidence = strings.Repeat("Scrollable evidence line. ", 45) + "END OF TARGET EVIDENCE"
module := &recordingModule{snapshot: app.Snapshot{ActiveProfile: "office", Targets: targets}}
model := resizedModel(t, module, themeModeNoColor, 80, 24)
for range 22 {
model = updateKey(model, "down")
}
view := model.View()
assertUsableFrame(t, view, 80, 24, "> ○ Disabled Product Target 22", "▶ Targets [focused]")
model = updateKey(model, "tab")
for range 70 {
model = updateKey(model, "down")
}
view = model.View()
assertUsableFrame(t, view, 80, 24,
"> ○ Disabled Product Target 22", "▶ Target details [focused]", "END OF", "TARGET EVIDENCE",
"↑/↓: Scroll", "Tab: Targets",
)
model = resize(model, 120, 36)
view = model.View()
assertUsableFrame(t, view, 120, 36, "> ○ Disabled Product Target 22", "END OF TARGET", "EVIDENCE", "▶ Target details [focused]")
if !sameLine(view, "Targets", "Target details") {
t.Fatalf("resized dashboard did not become side by side:\n%s", view)
}
model = resize(model, 80, 24)
assertUsableFrame(t, model.View(), 80, 24, "> ○ Disabled Product Target 22", "END OF", "TARGET EVIDENCE", "▶ Target details [focused]")
}