Files
kportal/internal/ui/wizard_manual_namespace_test.go
T
lukaszraczyloandGitHub 4748bc4be5 feat(ui): type the namespace when the cluster does not list them (#84)
Some users cannot list namespaces on a cluster. The add wizard showed
an error and offered no way forward.

The namespace step now switches to a text prompt when the list call
fails or returns nothing. The prompt shows the reason and checks that
the name is a valid DNS label. Esc from a later step returns to the
prompt.

The j and k keys now type into text fields. They moved the list cursor
before, so a name such as kube-system could not be typed.

Closes #66
2026-10-02 02:28:58 +01:00

105 lines
3.1 KiB
Go

package ui
import (
"errors"
"testing"
tea "github.com/charmbracelet/bubbletea"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func typeKeys(t *testing.T, m model, text string) {
t.Helper()
for _, r := range text {
m.handleAddWizardKeys(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{r}})
}
}
func TestNamespacesLoaded_ListFailureSwitchesToManualEntry(t *testing.T) {
m := newModelWithWizard(StepSelectNamespace)
m.ui.addWizard.loading = true
m.handleNamespacesLoaded(NamespacesLoadedMsg{err: errors.New("namespaces is forbidden")})
w := m.ui.addWizard
assert.True(t, w.namespaceManual)
assert.Equal(t, InputModeText, w.inputMode)
assert.NoError(t, w.error)
assert.False(t, w.loading)
assert.Contains(t, m.renderSelectNamespace(), "Enter Namespace")
assert.Contains(t, m.renderSelectNamespace(), "forbidden")
}
func TestNamespacesLoaded_EmptyListSwitchesToManualEntry(t *testing.T) {
m := newModelWithWizard(StepSelectNamespace)
m.handleNamespacesLoaded(NamespacesLoadedMsg{namespaces: []string{}})
assert.True(t, m.ui.addWizard.namespaceManual)
}
func TestNamespacesLoaded_ListedNamespacesKeepSelectionMode(t *testing.T) {
m := newModelWithWizard(StepSelectNamespace)
m.handleNamespacesLoaded(NamespacesLoadedMsg{namespaces: []string{"default", "kube-system"}})
w := m.ui.addWizard
assert.False(t, w.namespaceManual)
assert.Equal(t, InputModeList, w.inputMode)
assert.Equal(t, []string{"default", "kube-system"}, w.namespaces)
}
func TestManualNamespace_TypeAndConfirm(t *testing.T) {
m := newModelWithWizard(StepSelectNamespace)
m.handleNamespacesLoaded(NamespacesLoadedMsg{err: errors.New("forbidden")})
// k and j must be typed, not treated as navigation
typeKeys(t, m, "kube-jack")
assert.Equal(t, "kube-jack", m.ui.addWizard.textInput)
m.handleAddWizardEnter()
w := m.ui.addWizard
assert.Equal(t, "kube-jack", w.selectedNamespace)
assert.Equal(t, StepSelectResourceType, w.step)
assert.Equal(t, InputModeList, w.inputMode)
assert.Empty(t, w.textInput)
}
func TestManualNamespace_RejectsInvalidName(t *testing.T) {
m := newModelWithWizard(StepSelectNamespace)
m.handleNamespacesLoaded(NamespacesLoadedMsg{err: errors.New("forbidden")})
m.ui.addWizard.selectedNamespace = ""
for _, bad := range []string{"", "Has_Upper", "-leading", "trailing-"} {
m.ui.addWizard.textInput = bad
m.handleAddWizardEnter()
w := m.ui.addWizard
require.Error(t, w.error, "name %q", bad)
assert.Equal(t, StepSelectNamespace, w.step, "name %q", bad)
assert.Empty(t, w.selectedNamespace, "name %q", bad)
}
}
func TestManualNamespace_BackFromLaterStepRestoresTextInput(t *testing.T) {
m := newModelWithWizard(StepSelectResourceType)
m.ui.addWizard.namespaceManual = true
m.handleAddWizardKeys(tea.KeyMsg{Type: tea.KeyEsc})
w := m.ui.addWizard
assert.Equal(t, StepSelectNamespace, w.step)
assert.Equal(t, InputModeText, w.inputMode)
}
func TestKeysJK_StillNavigateInListMode(t *testing.T) {
m := newModelWithWizard(StepSelectResourceType)
m.ui.addWizard.inputMode = InputModeList
m.handleAddWizardKeys(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}})
assert.Equal(t, 1, m.ui.addWizard.cursor)
}