once-add/internal/tui/render_test.go
28allday 68c64265a6 once-add: deploy + remove Once apps at <name>.local
A small Go tool that wraps the `/etc/hosts` + `once deploy --disable-tls`
recipe needed to host a Once app on a single-label `<name>.local`. Adds
the hosts entry, runs the deploy, polls /up, and on removal cleans the
hosts line that the Once UI orphans (including the orphan-only case,
where the app is already gone).

Bubble Tea TUI for interactive use; non-interactive CLI for scripts.
Curated apps live in /etc/once-add/apps.toml; seeded with Writebook +
Campfire on first run.
2026-05-28 07:23:07 +01:00

76 lines
1.9 KiB
Go

package tui
import (
"fmt"
"strings"
"testing"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textinput"
"once-add/internal/config"
)
// testModel builds a model without touching /etc, with components initialised
// so View() never panics.
func testModel() model {
sp := spinner.New()
sp.Spinner = spinner.Dot
return model{
customInput: textinput.New(),
nameInput: textinput.New(),
spinner: sp,
apps: []config.App{
{Name: "Writebook", Image: "ghcr.io/basecamp/writebook", Description: "Books", Suggested: "book"},
},
}
}
func TestViewAllStates(t *testing.T) {
states := []state{
stateMenu, stateSelectApp, stateCustomImage, stateName, stateDeploying,
stateRemovePick, stateRemoveConfirm, stateRemoving, stateDone, stateError,
}
for _, st := range states {
m := testModel()
m.state = st
m.name = "book"
m.image = "ghcr.io/basecamp/writebook"
m.resultURL = "http://book.local"
m.removeHosts = []string{"book.local", "chat.local"}
m.removeTarget = "chat.local"
m.doneMsg = "Removed chat.local"
m.err = fmt.Errorf("boom")
out := m.View()
if !strings.Contains(out, "once-add") {
t.Errorf("state %d: view missing title:\n%s", st, out)
}
}
}
func TestRemoveDoneWording(t *testing.T) {
m := testModel()
m.state = stateDone
m.op = opRemove
m.doneMsg = "Removed chat.local"
if !strings.Contains(m.View(), "Removed chat.local") {
t.Errorf("remove done view missing message:\n%s", m.View())
}
}
func TestEmptyRemovePick(t *testing.T) {
m := testModel()
m.state = stateRemovePick
m.removeHosts = nil
if !strings.Contains(m.View(), "No deployed") {
t.Errorf("empty remove pick should say nothing to remove:\n%s", m.View())
}
}
func TestSelectShowsCustomRow(t *testing.T) {
m := testModel()
out := m.viewSelect()
if !strings.Contains(out, "Writebook") || !strings.Contains(out, "Custom image") {
t.Errorf("select view missing rows:\n%s", out)
}
}