diff --git a/internal/ui/snapshot_editor.go b/internal/ui/snapshot_editor.go index 8825246..85e6441 100644 --- a/internal/ui/snapshot_editor.go +++ b/internal/ui/snapshot_editor.go @@ -114,14 +114,17 @@ func NewSnapshotEditor(snap *snapshot.Snapshot) SnapshotEditorModel { } tabs[3] = editorTab{name: "Taps", icon: "🔌", items: tapItems, itemType: editorItemTap} - prefItems := make([]editorItem, len(snap.MacOSPrefs)) - for i, p := range snap.MacOSPrefs { - prefItems[i] = editorItem{ + var prefItems []editorItem + for _, p := range snap.MacOSPrefs { + if p.Domain == "" || p.Key == "" { + continue + } + prefItems = append(prefItems, editorItem{ name: fmt.Sprintf("%s.%s", p.Domain, p.Key), description: fmt.Sprintf("= %s (%s)", p.Value, p.Desc), selected: true, itemType: editorItemMacOSPref, - } + }) } tabs[4] = editorTab{name: "macOS Prefs", icon: "⚙️ ", items: prefItems, itemType: editorItemMacOSPref} @@ -208,11 +211,13 @@ func (m SnapshotEditorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { //nolint m.activeTab = (m.activeTab + 1) % len(m.tabs) m.cursor = 0 m.scrollOffset = 0 + return m, tea.ClearScreen case key.Matches(msg, keys.ShiftTab), key.Matches(msg, keys.Left): m.activeTab = (m.activeTab - 1 + len(m.tabs)) % len(m.tabs) m.cursor = 0 m.scrollOffset = 0 + return m, tea.ClearScreen case key.Matches(msg, keys.Up): if m.cursor > 0 { diff --git a/internal/ui/snapshot_editor_test.go b/internal/ui/snapshot_editor_test.go index f95d49e..6327aff 100644 --- a/internal/ui/snapshot_editor_test.go +++ b/internal/ui/snapshot_editor_test.go @@ -68,6 +68,25 @@ func TestNewSnapshotEditorItems(t *testing.T) { assert.Equal(t, "homebrew/core", m.tabs[3].items[0].name) } +func TestNewSnapshotEditorSkipsInvalidMacOSPrefs(t *testing.T) { + snap := makeTestSnapshot() + snap.MacOSPrefs = append(snap.MacOSPrefs, + snapshot.MacOSPref{Domain: "cirruslabs/cli", Key: ""}, // tap misclassified as pref + snapshot.MacOSPref{Domain: "", Key: "SomeKey"}, // empty domain + snapshot.MacOSPref{Domain: "com.apple.dock", Key: "tilesize", Value: "48"}, // valid + ) + m := NewSnapshotEditor(snap) + + // Only valid prefs (non-empty domain AND key) should appear in the macOS Prefs tab. + prefTab := m.tabs[4] + for _, item := range prefTab.items { + assert.NotEmpty(t, item.name, "pref item name must not be empty") + assert.Contains(t, item.name, ".", "pref item name must contain a dot separator") + } + // 2 from makeTestSnapshot + 1 valid new pref = 3 + assert.Equal(t, 3, len(prefTab.items)) +} + func TestNewSnapshotEditorAllItemsSelected(t *testing.T) { snap := makeTestSnapshot() m := NewSnapshotEditor(snap) @@ -751,6 +770,39 @@ func TestBuildEditedSnapshotAddedMacOSPrefSplitsOnLastDot(t *testing.T) { assert.Equal(t, "48", added.Value) } +func TestSnapshotEditorTabSwitchReturnsClearScreenCmd(t *testing.T) { + m := NewSnapshotEditor(makeTestSnapshot()) + + _, cmd := m.Update(tea.KeyMsg{Type: tea.KeyTab}) + assert.NotNil(t, cmd, "Tab should return tea.ClearScreen cmd") + + _, cmd = m.Update(tea.KeyMsg{Type: tea.KeyShiftTab}) + assert.NotNil(t, cmd, "ShiftTab should return tea.ClearScreen cmd") +} + +func TestSnapshotEditorViewTabIsolation(t *testing.T) { + snap := makeTestSnapshot() + snap.Packages.Taps = []string{"cirruslabs/cli", "hashicorp/tap"} + snap.MacOSPrefs = []snapshot.MacOSPref{ + {Domain: "com.apple.dock", Key: "tilesize", Value: "48", Desc: "Dock tile size"}, + } + m := NewSnapshotEditor(snap) + m.width = 80 + m.height = 30 + + // macOS Prefs tab must not show any tap items + m.activeTab = 4 + view := m.View() + assert.NotContains(t, view, "cirruslabs/cli", "tap item must not appear on macOS Prefs tab") + assert.Contains(t, view, "com.apple.dock.tilesize", "macOS pref must appear on macOS Prefs tab") + + // Taps tab must not show any macOS pref items + m.activeTab = 3 + view = m.View() + assert.Contains(t, view, "cirruslabs/cli", "tap must appear on Taps tab") + assert.NotContains(t, view, "com.apple.dock.tilesize", "macOS pref must not appear on Taps tab") +} + func TestSnapshotEditorAddedItemVisualBadge(t *testing.T) { m := NewSnapshotEditor(makeTestSnapshot()) m.width = 80