Files
superwork/tui/internal/tui/profiles_panel_test.go
T
2026-06-23 05:02:15 +08:00

265 lines
7.4 KiB
Go

package tui
import (
"strings"
"testing"
"superwork-tui/internal/cc"
"superwork-tui/internal/config"
"superwork-tui/internal/issue"
"superwork-tui/internal/store"
)
// ── profile picker tests ──────────────────────────────────────────────────────
func TestProfilePicker_NoProfilesDir_ShowsStatus(t *testing.T) {
m := New()
m.settings = &config.Settings{ProfilesDir: ""}
m.state = stateDetail
iss := issue.Issue{Number: 42}
m.detailIss = &iss
m2, _ := m.openProfilePicker(false)
if m2.state != stateDetail {
t.Errorf("state should stay stateDetail when no ProfilesDir, got %v", m2.state)
}
if !strings.Contains(m2.statusMsg, "profiles") {
t.Errorf("statusMsg should mention profiles, got %q", m2.statusMsg)
}
}
func TestProfilePicker_EscReturnsToDetail(t *testing.T) {
m := New()
m.settings = &config.Settings{ProfilesDir: t.TempDir()}
m.profilePickerPrevState = stateDetail
m.state = stateProfilePicker
m.profilePickerProfiles = []cc.ClaudeProfile{{Name: "dev", Path: "/p/dev.json"}}
result, _ := m.handleProfilePickerKey(keyMsg("esc"))
m2 := result.(Model)
if m2.state != stateDetail {
t.Errorf("expected stateDetail after esc, got %v", m2.state)
}
}
func TestProfilePicker_SelectSetsProfilePath(t *testing.T) {
m := New()
m.settings = &config.Settings{ProfilesDir: t.TempDir()}
m.state = stateProfilePicker
m.profilePickerPrevState = stateDetail
m.profilePickerForTest = false
m.profilePickerProfiles = []cc.ClaudeProfile{
{Name: "dev", Path: "/profiles/dev.json"},
{Name: "prod", Path: "/profiles/prod.json"},
}
m.profilePickerCursor = 1
iss := issue.Issue{Number: 7}
m.detailIss = &iss
result, _ := m.handleProfilePickerKey(keyMsg("enter"))
m2 := result.(Model)
if m2.state != stateDetail {
t.Errorf("expected stateDetail after selection, got %v", m2.state)
}
if m2.detailIss.ProfilePath != "/profiles/prod.json" {
t.Errorf("ProfilePath = %q, want /profiles/prod.json", m2.detailIss.ProfilePath)
}
}
func TestProfilePicker_SelectSetsTestProfilePath(t *testing.T) {
m := New()
m.settings = &config.Settings{ProfilesDir: t.TempDir()}
m.state = stateProfilePicker
m.profilePickerPrevState = stateDetail
m.profilePickerForTest = true
m.profilePickerProfiles = []cc.ClaudeProfile{
{Name: "test", Path: "/profiles/test.json"},
}
m.profilePickerCursor = 0
iss := issue.Issue{Number: 7}
m.detailIss = &iss
result, _ := m.handleProfilePickerKey(keyMsg("enter"))
m2 := result.(Model)
if m2.detailIss.TestProfilePath != "/profiles/test.json" {
t.Errorf("TestProfilePath = %q, want /profiles/test.json", m2.detailIss.TestProfilePath)
}
}
func TestProfilePicker_CursorNavigation(t *testing.T) {
m := New()
m.state = stateProfilePicker
m.profilePickerProfiles = []cc.ClaudeProfile{
{Name: "a", Path: "/a.json"},
{Name: "b", Path: "/b.json"},
{Name: "c", Path: "/c.json"},
}
m.profilePickerCursor = 0
result, _ := m.handleProfilePickerKey(keyMsg("j"))
m2 := result.(Model)
if m2.profilePickerCursor != 1 {
t.Errorf("cursor after j = %d, want 1", m2.profilePickerCursor)
}
result2, _ := m2.handleProfilePickerKey(keyMsg("k"))
m3 := result2.(Model)
if m3.profilePickerCursor != 0 {
t.Errorf("cursor after k = %d, want 0", m3.profilePickerCursor)
}
}
func TestProfilePickerView_ContainsProfiles(t *testing.T) {
m := New()
m.state = stateProfilePicker
m.profilePickerProfiles = []cc.ClaudeProfile{
{Name: "dev", Path: "/profiles/dev.json"},
{Name: "prod", Path: "/profiles/prod.json"},
}
m.profilePickerCursor = 0
out := m.profilePickerView()
for _, want := range []string{"dev", "prod", "/profiles/dev.json"} {
if !strings.Contains(out, want) {
t.Errorf("profilePickerView missing %q", want)
}
}
}
// ── profile grid tests ────────────────────────────────────────────────────────
func TestProfileGrid_OpenLoadsData(t *testing.T) {
m := New()
m2, cmd := m.openProfileGrid()
if m2.state != stateProfileGrid {
t.Errorf("state = %v, want stateProfileGrid", m2.state)
}
if cmd == nil {
t.Error("openProfileGrid should return a load cmd")
}
}
func TestProfileGrid_EscReturnsToBoard(t *testing.T) {
m := New()
m.state = stateProfileGrid
m.profileGridData = store.ProfilesData{Profiles: []string{"dev"}, Rows: nil}
result, _ := m.handleProfileGridKey(keyMsg("esc"))
m2 := result.(Model)
if m2.state != stateLoaded {
t.Errorf("expected stateLoaded after esc, got %v", m2.state)
}
}
func TestProfileGrid_EditCellAndSave(t *testing.T) {
tmpDir := t.TempDir()
restore := overrideWorkspaceRoot(tmpDir)
defer restore()
m := New()
m.state = stateProfileGrid
m.profileGridData = store.ProfilesData{
Profiles: []string{"dev", "prod"},
Rows: []store.ProfileRow{
{Key: "model", Values: map[string]string{"dev": "opus", "prod": "sonnet"}},
},
}
m.profileGridRow = 0
m.profileGridCol = 1 // "dev" column
// Enter edit mode
result, _ := m.handleProfileGridKey(keyMsg("enter"))
m2 := result.(Model)
if !m2.profileGridEditing {
t.Fatal("expected editing mode after enter on value cell")
}
// Type a new value
m2.profileGridEdit.SetValue("haiku")
// Commit
result2, _ := m2.handleProfileGridKey(keyMsg("enter"))
m3 := result2.(Model)
if m3.profileGridEditing {
t.Error("editing should be false after commit")
}
if m3.profileGridData.Rows[0].Values["dev"] != "haiku" {
t.Errorf("dev value = %q, want haiku", m3.profileGridData.Rows[0].Values["dev"])
}
// Save
_, saveCmd := m3.handleProfileGridKey(keyMsg("ctrl+s"))
if saveCmd == nil {
t.Fatal("ctrl+s should return a save cmd")
}
msg := saveCmd()
saved, ok := msg.(profileGridSavedMsg)
if !ok {
t.Fatalf("expected profileGridSavedMsg, got %T", msg)
}
if saved.err != nil {
t.Errorf("save error: %v", saved.err)
}
// Verify persisted
loaded, err := store.ReadProfiles(tmpDir)
if err != nil {
t.Fatal(err)
}
if loaded.Rows[0].Values["dev"] != "haiku" {
t.Errorf("persisted dev = %q, want haiku", loaded.Rows[0].Values["dev"])
}
}
func TestProfileGrid_AddRow(t *testing.T) {
m := New()
m.state = stateProfileGrid
m.profileGridData = store.ProfilesData{
Profiles: []string{"dev"},
Rows: []store.ProfileRow{},
}
// Press 'a' to add row
result, _ := m.handleProfileGridKey(keyMsg("a"))
m2 := result.(Model)
if !m2.profileGridAddingKey {
t.Error("expected profileGridAddingKey = true after pressing a")
}
// Type key name
m2.profileGridNewKey.SetValue("timeout")
// Confirm
result2, _ := m2.handleProfileGridKey(keyMsg("enter"))
m3 := result2.(Model)
if m3.profileGridAddingKey {
t.Error("profileGridAddingKey should be false after confirm")
}
if len(m3.profileGridData.Rows) != 1 {
t.Errorf("rows = %d, want 1", len(m3.profileGridData.Rows))
}
if m3.profileGridData.Rows[0].Key != "timeout" {
t.Errorf("row key = %q, want timeout", m3.profileGridData.Rows[0].Key)
}
}
func TestProfileGridView_ContainsData(t *testing.T) {
m := New()
m.state = stateProfileGrid
m.profileGridData = store.ProfilesData{
Profiles: []string{"dev", "prod"},
Rows: []store.ProfileRow{
{Key: "model", Values: map[string]string{"dev": "opus", "prod": "sonnet"}},
},
}
out := m.profileGridView()
for _, want := range []string{"Profile Grid", "dev", "prod", "model", "opus", "sonnet"} {
if !strings.Contains(out, want) {
t.Errorf("profileGridView missing %q", want)
}
}
}