package main import ( "os" "path/filepath" "strings" "testing" "github.com/charmbracelet/lipgloss" "todoapp/internal/todos" ) func assertFits(t *testing.T, view string, width, height int) { t.Helper() lines := strings.Split(strings.TrimSuffix(view, "\n"), "\n") if len(lines) > height { t.Fatalf("view is %d lines in %d-row terminal:\n%s", len(lines), height, view) } for _, line := range lines { if lipgloss.Width(line) > width { t.Fatalf("line is %d cells in %d-column terminal: %q", lipgloss.Width(line), width, line) } } } func TestStyledScreensFitTerminals(t *testing.T) { for _, size := range [][2]int{{80, 24}, {50, 14}, {32, 10}} { width, height := size[0], size[1] app := model{width: width, height: height, project: "/tmp/project", todosDir: "/tmp/project/.pi/todos", items: []todos.Todo{ {ID: "deadbeef", Title: "A long title for a narrow terminal", Status: "open", Tags: []string{"qa"}, Body: "# Long heading\n\nBody text."}, {ID: "cafebabe", Title: "Another todo", Status: "in_progress_with_long_status", Tags: []string{"a very long tag that must be clipped"}, Body: "Second body"}, }} assertFits(t, app.View(), width, height) if !strings.Contains(app.View(), "› ") || !strings.Contains(app.View(), "Search:") { t.Fatal("selection or search missing from styled list") } app = testKey(app, runeKey('/')) app = testKey(app, runeKey('z')) if !strings.Contains(app.View(), "No matching todos") { t.Fatal("search empty state missing") } assertFits(t, app.View(), width, height) app.search, app.query = false, "" app.detail = true assertFits(t, app.View(), width, height) app.detail = false // Render an editor without touching the filesystem. app.editor = &editor{creating: true, fields: [3]string{"A title that goes well beyond the width of this small window", "qa, pi", "Line one\nLine two"}} app.editor.selectField(0) if !strings.Contains(app.View(), "▏") { t.Fatalf("title cursor hidden at width %d: %s", width, app.View()) } assertFits(t, app.View(), width, height) app.editor.selectField(2) assertFits(t, app.View(), width, height) app.confirm = "close" assertFits(t, app.View(), width, height) } } func TestNoColorAndMalformedWarning(t *testing.T) { t.Setenv("NO_COLOR", "1") project := t.TempDir() dir := todos.Dir(project) if err := os.MkdirAll(dir, 0700); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "deadbeef.md"), []byte("invalid"), 0600); err != nil { t.Fatal(err) } app, err := newModel(project) if err != nil { t.Fatal(err) } view := app.View() if !strings.Contains(view, "Warning") || !strings.Contains(view, "No todos yet") || strings.Contains(view, "\x1b[") { t.Fatalf("no-color warning/empty state is unclear: %s", view) } assertFits(t, view, 80, 24) }