Files
superwork/tui/internal/tui/scroll_test.go
T
2026-06-23 05:02:15 +08:00

176 lines
4.7 KiB
Go

package tui
import (
"fmt"
"strings"
"testing"
"charm.land/lipgloss/v2"
"superwork-tui/internal/issue"
)
func makeDoneIssues(n int) []issue.Issue {
issues := make([]issue.Issue, n)
for i := range issues {
issues[i] = issue.Issue{Number: i + 1, Title: fmt.Sprintf("Issue %d", i+1), Column: issue.ColumnDone}
}
return issues
}
func makeInProgressIssues(n int) []issue.Issue {
issues := make([]issue.Issue, n)
for i := range issues {
issues[i] = issue.Issue{Number: i + 1, Title: fmt.Sprintf("Issue %d", i+1), Column: issue.ColumnInProgress}
}
return issues
}
func makeTodoIssues(n int) []issue.Issue {
issues := make([]issue.Issue, n)
for i := range issues {
issues[i] = issue.Issue{Number: i + 1, Title: fmt.Sprintf("Issue %d", i+1), Column: issue.ColumnTodo}
}
return issues
}
// TestRenderColumn_HeightBound: 30 done issues with boxH=20 must render exactly 20 lines (outer) and show ▼.
func TestRenderColumn_HeightBound(t *testing.T) {
doneIssues := makeDoneIssues(30)
all := make([]issue.Issue, len(doneIssues))
copy(all, doneIssues)
var buckets [4][]issue.Issue
buckets[3] = doneIssues
m := Model{
state: stateLoaded,
issues: all,
buckets: buckets,
width: 120,
height: 40,
colIdx: 0,
rowIdx: 0,
}
const boxH = 20
result := m.renderColumn(3, 30, boxH)
h := lipgloss.Height(result)
// outer box = inner(boxH-2) + 2 border rows = boxH
if h != boxH {
t.Errorf("renderColumn height = %d, want %d", h, boxH)
}
if !strings.Contains(result, "▼") {
t.Errorf("renderColumn missing ▼ indicator when cards overflow; got:\n%s", result)
}
}
// TestRenderColumn_ScrollIntoView: 20 in-progress issues, selected at rowIdx=15.
// boxH=10 → cardsH=7, so card at idx=15 requires scrolling. Expect ▲ and card visible.
func TestRenderColumn_ScrollIntoView(t *testing.T) {
inpIssues := makeInProgressIssues(20)
var buckets [4][]issue.Issue
buckets[1] = inpIssues
m := Model{
state: stateLoaded,
issues: inpIssues,
buckets: buckets,
width: 120,
height: 40,
colIdx: 1,
rowIdx: 15,
}
const boxH = 10 // cardsH = 10-3 = 7; card at idx=15 needs scroll
result := m.renderColumn(1, 30, boxH)
want := fmt.Sprintf("Issue %d", 16) // rowIdx=15 → Number=16
if !strings.Contains(result, want) {
t.Errorf("renderColumn missing selected card %q after scroll; got:\n%s", want, result)
}
if !strings.Contains(result, "▲") {
t.Errorf("renderColumn missing ▲ indicator when scrolled down; got:\n%s", result)
}
}
// TestBoardView_HeightBound: board with height=30 and 30 done issues — column portion height = height-2.
func TestBoardView_HeightBound(t *testing.T) {
doneIssues := makeDoneIssues(30)
var buckets [4][]issue.Issue
buckets[3] = doneIssues
m := Model{
state: stateLoaded,
issues: doneIssues,
buckets: buckets,
width: 120,
height: 30,
colIdx: 0,
rowIdx: 0,
}
v := m.boardView()
// Extract board portion (everything before the final help line).
lines := strings.Split(v, "\n")
// Help line is the last non-empty line. Board = height-2 outer rows.
// Total view lines ≤ m.height (board rows + 1 help row).
h := lipgloss.Height(v)
if h > m.height {
t.Errorf("boardView total height = %d, want ≤ %d", h, m.height)
}
_ = lines
}
// TestRenderColumn_EmptyColEqualHeight: empty col 0 and 5-issue col 1 must both render at boxH.
func TestRenderColumn_EmptyColEqualHeight(t *testing.T) {
inpIssues := makeInProgressIssues(5)
var buckets [4][]issue.Issue
buckets[1] = inpIssues
m := Model{
state: stateLoaded,
issues: inpIssues,
buckets: buckets,
width: 120,
height: 40,
colIdx: 1,
rowIdx: 0,
}
const boxH = 20
emptyCol := m.renderColumn(0, 30, boxH)
filledCol := m.renderColumn(1, 30, boxH)
hEmpty := lipgloss.Height(emptyCol)
hFilled := lipgloss.Height(filledCol)
if hEmpty != boxH {
t.Errorf("empty col height=%d, want %d", hEmpty, boxH)
}
if hFilled != boxH {
t.Errorf("filled col height=%d, want %d", hFilled, boxH)
}
}
// TestRenderColumn_TodoScrollIntoView: 15 todo issues, selected at rowIdx=12 → card visible + ▲ shown.
func TestRenderColumn_TodoScrollIntoView(t *testing.T) {
todoIssues := makeTodoIssues(15)
var buckets [4][]issue.Issue
buckets[0] = todoIssues
m := Model{
state: stateLoaded,
issues: todoIssues,
buckets: buckets,
width: 120,
height: 40,
colIdx: 0,
rowIdx: 12,
}
result := m.renderColumn(0, 30, 15)
want := fmt.Sprintf("Issue %d", 13) // rowIdx=12 → index 12 → Number=13
if !strings.Contains(result, want) {
t.Errorf("todo renderColumn missing selected card %q after scroll; got:\n%s", want, result)
}
if !strings.Contains(result, "▲") {
t.Errorf("todo renderColumn missing ▲ indicator when scrolled down; got:\n%s", result)
}
}