test: tests unitarios para pantalla de tests del dashboard

Tests para TestMenuOptions, updateTestsScreen (navegacion, seleccion,
generacion de intents), viewTests (render, cursor, last run),
testKindLabel, testKindIntent, y navegacion desde main/server menus.

Issue: 0023

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 15:43:56 +00:00
parent 509d456275
commit 1abc1ef509
+347
View File
@@ -0,0 +1,347 @@
package tui
import (
"strings"
"testing"
)
// ── TestMenuOptions ─────────────────────────────────────────────────────
func TestTestMenuOptions_Count(t *testing.T) {
opts := TestMenuOptions()
if len(opts) != 4 {
t.Fatalf("expected 4 test menu options, got %d", len(opts))
}
}
func TestTestMenuOptions_Labels(t *testing.T) {
opts := TestMenuOptions()
expected := []string{"Go Tests", "E2E Tests", "E2E Tests (headed)", "All Tests"}
for i, want := range expected {
if opts[i].Label != want {
t.Errorf("option[%d]: expected label %q, got %q", i, want, opts[i].Label)
}
}
}
func TestMainMenuOptions_IncludesTests(t *testing.T) {
opts := MainMenuOptions()
found := false
for _, opt := range opts {
if opt.Label == "Tests" {
found = true
break
}
}
if !found {
t.Error("MainMenuOptions should include 'Tests'")
}
}
func TestMainMenuOptions_TestsBeforeQuit(t *testing.T) {
opts := MainMenuOptions()
testsIdx, quitIdx := -1, -1
for i, opt := range opts {
if opt.Label == "Tests" {
testsIdx = i
}
if opt.Label == "Quit" {
quitIdx = i
}
}
if testsIdx < 0 || quitIdx < 0 {
t.Fatal("expected both Tests and Quit in menu")
}
if testsIdx >= quitIdx {
t.Errorf("Tests (index %d) should come before Quit (index %d)", testsIdx, quitIdx)
}
}
func TestServerMenuOptions_NoRunTests(t *testing.T) {
for _, running := range []bool{true, false} {
opts := ServerMenuOptions(running)
for _, opt := range opts {
if opt.Label == "Run Tests" {
t.Errorf("ServerMenuOptions(running=%v) should not have 'Run Tests', found it", running)
}
}
}
}
func TestServerMenuOptions_HasTests(t *testing.T) {
for _, running := range []bool{true, false} {
opts := ServerMenuOptions(running)
found := false
for _, opt := range opts {
if opt.Label == "Tests" {
found = true
}
}
if !found {
t.Errorf("ServerMenuOptions(running=%v) should have 'Tests'", running)
}
}
}
// ── updateTestsScreen ───────────────────────────────────────────────────
func TestUpdateTestsScreen_Navigation(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 0, WindowHeight: 40}
m, _ = Update(m, KeyMsg{Str: "down"})
if m.Cursor != 1 {
t.Errorf("expected cursor 1 after down, got %d", m.Cursor)
}
m, _ = Update(m, KeyMsg{Str: "up"})
if m.Cursor != 0 {
t.Errorf("expected cursor 0 after up, got %d", m.Cursor)
}
// Can't go below 0
m, _ = Update(m, KeyMsg{Str: "up"})
if m.Cursor != 0 {
t.Errorf("expected cursor 0 clamped, got %d", m.Cursor)
}
}
func TestUpdateTestsScreen_Back(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 2}
m, _ = Update(m, KeyMsg{Str: "0"})
if m.Screen != ScreenMain {
t.Errorf("expected ScreenMain, got %d", m.Screen)
}
if m.Cursor != 0 {
t.Errorf("expected cursor reset to 0, got %d", m.Cursor)
}
}
func TestUpdateTestsScreen_SelectGoTests(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 0}
m, intents := Update(m, KeyMsg{Str: "enter"})
if len(intents) != 1 || intents[0].Kind != IntentRunGoTests {
t.Errorf("expected IntentRunGoTests, got %v", intents)
}
if m.LastTestKind != TestKindGo {
t.Errorf("expected LastTestKind=TestKindGo, got %d", m.LastTestKind)
}
}
func TestUpdateTestsScreen_SelectE2ETests(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 1}
_, intents := Update(m, KeyMsg{Str: "enter"})
if len(intents) != 1 || intents[0].Kind != IntentRunE2ETests {
t.Errorf("expected IntentRunE2ETests, got %v", intents)
}
}
func TestUpdateTestsScreen_SelectE2EHeaded(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 2}
_, intents := Update(m, KeyMsg{Str: "enter"})
if len(intents) != 1 || intents[0].Kind != IntentRunE2EHeadTests {
t.Errorf("expected IntentRunE2EHeadTests, got %v", intents)
}
}
func TestUpdateTestsScreen_SelectAllTests(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 3}
_, intents := Update(m, KeyMsg{Str: "enter"})
if len(intents) != 1 || intents[0].Kind != IntentRunAllTests {
t.Errorf("expected IntentRunAllTests, got %v", intents)
}
}
// ── MsgTestsDone ────────────────────────────────────────────────────────
func TestMsgTestsDone_SetsKindAndStatus(t *testing.T) {
m := Model{Screen: ScreenTests}
m, _ = Update(m, MsgTestsDone{Kind: TestKindE2E, Passed: true, Output: []string{"ok"}})
if m.Screen != ScreenTestOutput {
t.Errorf("expected ScreenTestOutput, got %d", m.Screen)
}
if m.LastTestKind != TestKindE2E {
t.Errorf("expected LastTestKind=TestKindE2E, got %d", m.LastTestKind)
}
if !strings.Contains(m.StatusMsg, "PASSED") {
t.Errorf("expected PASSED in status, got %q", m.StatusMsg)
}
if !strings.Contains(m.StatusMsg, "E2E") {
t.Errorf("expected E2E in status, got %q", m.StatusMsg)
}
}
func TestMsgTestsDone_Failed(t *testing.T) {
m := Model{}
m, _ = Update(m, MsgTestsDone{Kind: TestKindGo, Passed: false, Output: []string{"FAIL"}})
if !strings.Contains(m.StatusMsg, "FAILED") {
t.Errorf("expected FAILED in status, got %q", m.StatusMsg)
}
}
// ── updateTestOutput ────────────────────────────────────────────────────
func TestUpdateTestOutput_BackGoesToTests(t *testing.T) {
m := Model{Screen: ScreenTestOutput, LastTestKind: TestKindGo}
m, _ = Update(m, KeyMsg{Str: "0"})
if m.Screen != ScreenTests {
t.Errorf("expected ScreenTests, got %d", m.Screen)
}
}
func TestUpdateTestOutput_RerunUsesLastKind(t *testing.T) {
m := Model{Screen: ScreenTestOutput, LastTestKind: TestKindE2E, WindowHeight: 40}
_, intents := Update(m, KeyMsg{Str: "r"})
if len(intents) != 1 || intents[0].Kind != IntentRunE2ETests {
t.Errorf("expected IntentRunE2ETests, got %v", intents)
}
}
func TestUpdateTestOutput_RerunDefaultsToGo(t *testing.T) {
m := Model{Screen: ScreenTestOutput, LastTestKind: TestKindNone, WindowHeight: 40}
_, intents := Update(m, KeyMsg{Str: "r"})
if len(intents) != 1 || intents[0].Kind != IntentRunGoTests {
t.Errorf("expected IntentRunGoTests as default, got %v", intents)
}
}
// ── viewTests ───────────────────────────────────────────────────────────
func TestViewTests_ShowsOptions(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 0, WindowWidth: 80, WindowHeight: 40}
out := View(m)
if !strings.Contains(out, "Go Tests") {
t.Error("expected 'Go Tests' in view")
}
if !strings.Contains(out, "E2E Tests") {
t.Error("expected 'E2E Tests' in view")
}
if !strings.Contains(out, "All Tests") {
t.Error("expected 'All Tests' in view")
}
}
func TestViewTests_ShowsCursor(t *testing.T) {
m := Model{Screen: ScreenTests, Cursor: 1, WindowWidth: 80, WindowHeight: 40}
out := View(m)
// Cursor on E2E Tests (index 1)
lines := strings.Split(out, "\n")
foundCursor := false
for _, line := range lines {
if strings.Contains(line, "> ") && strings.Contains(line, "E2E Tests") && !strings.Contains(line, "(headed)") {
foundCursor = true
}
}
if !foundCursor {
t.Error("expected cursor on E2E Tests")
}
}
func TestViewTests_ShowsLastRun(t *testing.T) {
m := Model{
Screen: ScreenTests,
Cursor: 0,
WindowWidth: 80,
WindowHeight: 40,
LastTestKind: TestKindGo,
StatusMsg: "Go Tests PASSED",
}
out := View(m)
if !strings.Contains(out, "Last run:") {
t.Error("expected 'Last run:' in view")
}
if !strings.Contains(out, "PASSED") {
t.Error("expected PASSED in last run")
}
}
func TestViewTestOutput_ShowsKindInTitle(t *testing.T) {
m := Model{
Screen: ScreenTestOutput,
LastTestKind: TestKindE2E,
StatusMsg: "E2E Tests PASSED",
LogLines: []string{"ok"},
WindowWidth: 80,
WindowHeight: 40,
}
out := View(m)
if !strings.Contains(out, "Test Results — E2E Tests") {
t.Errorf("expected 'Test Results — E2E Tests' in view, got:\n%s", out)
}
}
// ── Main menu Tests navigation ──────────────────────────────────────────
func TestMainMenu_TestsNavigation(t *testing.T) {
m := Model{Screen: ScreenMain, Cursor: 2} // Tests is at index 2
m, intents := Update(m, KeyMsg{Str: "enter"})
if m.Screen != ScreenTests {
t.Errorf("expected ScreenTests, got %d", m.Screen)
}
if len(intents) != 0 {
t.Errorf("expected no intents for Tests nav, got %v", intents)
}
}
// ── Server menu Tests navigation ────────────────────────────────────────
func TestServerMenu_TestsNavigation(t *testing.T) {
// "Tests" is the last option in both running/stopped menus
opts := ServerMenuOptions(false)
testsIdx := -1
for i, o := range opts {
if o.Label == "Tests" {
testsIdx = i
}
}
if testsIdx < 0 {
t.Fatal("Tests not found in server menu")
}
m := Model{Screen: ScreenServer, Cursor: testsIdx}
m, _ = Update(m, KeyMsg{Str: "enter"})
if m.Screen != ScreenTests {
t.Errorf("expected ScreenTests, got %d", m.Screen)
}
}
// ── testKindLabel ───────────────────────────────────────────────────────
func TestTestKindLabel(t *testing.T) {
cases := []struct {
kind TestKind
want string
}{
{TestKindGo, "Go Tests"},
{TestKindE2E, "E2E Tests"},
{TestKindE2EHead, "E2E Tests (headed)"},
{TestKindAll, "All Tests"},
{TestKindNone, "Tests"},
}
for _, tc := range cases {
got := testKindLabel(tc.kind)
if got != tc.want {
t.Errorf("testKindLabel(%d) = %q, want %q", tc.kind, got, tc.want)
}
}
}
// ── testKindIntent ──────────────────────────────────────────────────────
func TestTestKindIntent(t *testing.T) {
cases := []struct {
kind TestKind
want IntentKind
}{
{TestKindGo, IntentRunGoTests},
{TestKindE2E, IntentRunE2ETests},
{TestKindE2EHead, IntentRunE2EHeadTests},
{TestKindAll, IntentRunAllTests},
{TestKindNone, ""},
}
for _, tc := range cases {
got := testKindIntent(tc.kind)
if got != tc.want {
t.Errorf("testKindIntent(%d) = %q, want %q", tc.kind, got, tc.want)
}
}
}