mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-06-28 05:26:27 +00:00
test: cover ui handlers/views/commands/table
internal/ui: 27.9% -> 79.8%. Adds three test files (~3300 lines):
- wizard_handlers_extended_test.go: keyboard branches not previously
covered (ctrl+c, pgup/pgdn, search filter typing, port-checked
failure path, alias text edit, focus toggling, error states),
plus removeForwardsCmd / removeForwardByIDCmd against real Mutator
+ tempdir config (dedup + at-least-one-namespace validation).
- wizard_views_test.go: every renderXxx path with a populated
AddWizardState — context/namespace selectors, resource selection,
port entry, http log list/detail, success, scroll indicators.
- table_test.go: AddForward / UpdateStatus / SetError / Clear /
FilterStrings flows.
Test-only fixups noted by agent:
- getFilteredEntries silently skips StatusCode==0 entries (only
completed responses are visible). Tests now seed StatusCode=200.
- handleForwardSaved leaves step=StepConfirmation on save error
rather than advancing to StepSuccess; assertion corrected.
- removeForwardsCmd needs >=2 forwards in a context for dedup tests
so removing one leaves the context non-empty (validator rejects
empty contexts).
go test -race -count=1 ./... clean across all 14 packages.
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestNewTableUI tests the constructor.
|
||||
func TestNewTableUI(t *testing.T) {
|
||||
tui := NewTableUI(false)
|
||||
require.NotNil(t, tui)
|
||||
assert.NotNil(t, tui.forwards)
|
||||
assert.False(t, tui.verbose)
|
||||
|
||||
tuiVerbose := NewTableUI(true)
|
||||
assert.True(t, tuiVerbose.verbose)
|
||||
}
|
||||
|
||||
// TestTableUI_AddForward covers the happy path and resource-parsing branches.
|
||||
func TestTableUI_AddForward(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resource string
|
||||
alias string
|
||||
expectedType string
|
||||
expectedName string
|
||||
expectedAlias string
|
||||
}{
|
||||
{
|
||||
name: "pod with prefix",
|
||||
resource: "pod/my-app",
|
||||
alias: "alias",
|
||||
expectedType: "pod",
|
||||
expectedName: "my-app",
|
||||
expectedAlias: "alias",
|
||||
},
|
||||
{
|
||||
name: "service resource",
|
||||
resource: "service/postgres",
|
||||
alias: "",
|
||||
expectedType: "service",
|
||||
expectedName: "postgres",
|
||||
expectedAlias: "postgres", // Falls back to resource name
|
||||
},
|
||||
{
|
||||
name: "no type prefix defaults to pod",
|
||||
resource: "my-pod",
|
||||
alias: "",
|
||||
expectedType: "pod",
|
||||
expectedName: "my-pod",
|
||||
expectedAlias: "my-pod",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tui := NewTableUI(false)
|
||||
fwd := &config.Forward{
|
||||
Resource: tt.resource,
|
||||
Port: 8080,
|
||||
LocalPort: 8080,
|
||||
Alias: tt.alias,
|
||||
}
|
||||
tui.AddForward("id-1", fwd)
|
||||
|
||||
tui.mu.RLock()
|
||||
defer tui.mu.RUnlock()
|
||||
|
||||
require.Len(t, tui.forwards, 1)
|
||||
status := tui.forwards["id-1"]
|
||||
assert.Equal(t, tt.expectedType, status.Type)
|
||||
assert.Equal(t, tt.expectedName, status.Resource)
|
||||
assert.Equal(t, tt.expectedAlias, status.Alias)
|
||||
assert.Equal(t, "Starting", status.Status)
|
||||
assert.Equal(t, 8080, status.RemotePort)
|
||||
assert.Equal(t, 8080, status.LocalPort)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestTableUI_UpdateStatus verifies status mutation.
|
||||
func TestTableUI_UpdateStatus(t *testing.T) {
|
||||
tui := NewTableUI(false)
|
||||
fwd := &config.Forward{Resource: "pod/app", Port: 80, LocalPort: 8080}
|
||||
tui.AddForward("id-1", fwd)
|
||||
|
||||
tui.UpdateStatus("id-1", "Active")
|
||||
|
||||
tui.mu.RLock()
|
||||
assert.Equal(t, "Active", tui.forwards["id-1"].Status)
|
||||
tui.mu.RUnlock()
|
||||
|
||||
// Updating non-existent ID must not panic.
|
||||
tui.UpdateStatus("nonexistent", "Active")
|
||||
}
|
||||
|
||||
// TestTableUI_GetForward covers the lookup path.
|
||||
func TestTableUI_GetForward(t *testing.T) {
|
||||
tui := NewTableUI(false)
|
||||
fwd := &config.Forward{Resource: "pod/app", Port: 80, LocalPort: 8080}
|
||||
tui.AddForward("id-1", fwd)
|
||||
|
||||
got := tui.GetForward("id-1")
|
||||
require.NotNil(t, got)
|
||||
assert.Equal(t, "app", got.Resource)
|
||||
|
||||
missing := tui.GetForward("nonexistent")
|
||||
assert.Nil(t, missing)
|
||||
}
|
||||
|
||||
// TestTableUI_Remove tests deletion.
|
||||
func TestTableUI_Remove(t *testing.T) {
|
||||
tui := NewTableUI(false)
|
||||
fwd := &config.Forward{Resource: "pod/app", Port: 80, LocalPort: 8080}
|
||||
tui.AddForward("id-1", fwd)
|
||||
tui.AddForward("id-2", fwd)
|
||||
|
||||
tui.Remove("id-1")
|
||||
|
||||
tui.mu.RLock()
|
||||
defer tui.mu.RUnlock()
|
||||
assert.Len(t, tui.forwards, 1)
|
||||
assert.Nil(t, tui.forwards["id-1"])
|
||||
assert.NotNil(t, tui.forwards["id-2"])
|
||||
}
|
||||
|
||||
// TestTruncate covers the truncation helper.
|
||||
func TestTruncate(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
maxLen int
|
||||
}{
|
||||
{"hello", "hello", 10},
|
||||
{"hello world", "hello...", 8},
|
||||
{"hi", "hi", 2},
|
||||
{"hi!", "hi", 2}, // maxLen <= 3 branch: no ellipsis
|
||||
{"abcd", "abc", 3}, // maxLen <= 3 branch
|
||||
{"", "", 5},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.input+"_"+string(rune('0'+tt.maxLen)), func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, truncate(tt.input, tt.maxLen))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestHyperlink verifies the OSC-8 escape sequence is produced.
|
||||
func TestHyperlink(t *testing.T) {
|
||||
result := hyperlink("http://localhost:8080", "8080→")
|
||||
assert.Contains(t, result, "http://localhost:8080")
|
||||
assert.Contains(t, result, "8080→")
|
||||
// Must contain OSC-8 opener and closer
|
||||
assert.Contains(t, result, "\x1b]8;;")
|
||||
assert.Contains(t, result, "\x1b\\")
|
||||
}
|
||||
|
||||
// TestFormatStatusWithIndicator covers all status branches.
|
||||
func TestFormatStatusWithIndicator(t *testing.T) {
|
||||
statuses := []string{"Active", "Starting", "Reconnecting", "Error", "Failed", "Unknown"}
|
||||
for _, s := range statuses {
|
||||
t.Run(s, func(t *testing.T) {
|
||||
result := formatStatusWithIndicator(s)
|
||||
// Must contain the original status string.
|
||||
assert.Contains(t, result, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user