120 lines
4.2 KiB
Go
120 lines
4.2 KiB
Go
package tui
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"charm.land/lipgloss/v2"
|
|
"superwork-tui/internal/issue"
|
|
)
|
|
|
|
// TestBoardView_NeverExceedsTerminalHeight reproduces the interactive overflow
|
|
// bug: with double-width CJK titles, cards wrap inside the fixed-width column box
|
|
// to more rows than windowCards budgeted (it measured pre-wrap heights), so the
|
|
// board grew taller than the terminal and the altscreen renderer pushed headers
|
|
// and short columns off the top. The board must always fit m.height.
|
|
func TestBoardView_NeverExceedsTerminalHeight(t *testing.T) {
|
|
mk := func(n int, col issue.Column, title string) issue.Issue {
|
|
return issue.Issue{Number: n, Title: title, Column: col, PR: "240", Branch: "feature/abc"}
|
|
}
|
|
var issues []issue.Issue
|
|
for i := 0; i < 11; i++ {
|
|
issues = append(issues, mk(238-i, issue.ColumnTodo, "支持部署时使用客户自定义域名并自动签发证书与续期"))
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
issues = append(issues, mk(239-i, issue.ColumnReview, "分销裂变系统V1:一级分销 + 邀请注册归因 + 订单返佣 + T+30 结算"))
|
|
}
|
|
for i := 0; i < 101; i++ {
|
|
issues = append(issues, mk(226-i, issue.ColumnDone, "充值页面前端完全重构为电商风格(含 PC/移动端专用 UI)"))
|
|
}
|
|
|
|
for _, dims := range [][2]int{{250, 55}, {200, 50}, {180, 40}, {160, 30}} {
|
|
for _, colIdx := range []int{0, 3} {
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: issues,
|
|
buckets: bucketize(issues),
|
|
width: dims[0],
|
|
height: dims[1],
|
|
colIdx: colIdx,
|
|
statusMsg: "webhook:端口 17421 已被占用",
|
|
hasChanges: true,
|
|
}
|
|
out := m.boardView()
|
|
if h := lipgloss.Height(out); h > m.height {
|
|
t.Errorf("dims=%v colIdx=%d: boardView height %d exceeds terminal height %d", dims, colIdx, h, m.height)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBoardView_ShowsAllNonEmptyColumns(t *testing.T) {
|
|
var issues []issue.Issue
|
|
for i := 0; i < 11; i++ {
|
|
issues = append(issues, issue.Issue{Number: 1000 + i, Title: "TODOCARD", Column: issue.ColumnTodo})
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
issues = append(issues, issue.Issue{Number: 2000 + i, Title: "REVIEWCARD", Column: issue.ColumnReview})
|
|
}
|
|
for i := 0; i < 101; i++ {
|
|
issues = append(issues, issue.Issue{Number: 3000 + i, Title: "DONECARD", Column: issue.ColumnDone})
|
|
}
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: issues,
|
|
buckets: bucketize(issues),
|
|
width: 200,
|
|
height: 50,
|
|
}
|
|
out := m.boardView()
|
|
for _, want := range []string{"TODOCARD", "REVIEWCARD", "DONECARD"} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("%s missing from boardView", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Realistic: long wrapping Chinese titles, badges, screenshot-like dimensions,
|
|
// and selection on the done column (rightmost). Reproduces the real board shape.
|
|
func TestBoardView_RealisticDistribution(t *testing.T) {
|
|
mk := func(n int, col issue.Column, title string) issue.Issue {
|
|
return issue.Issue{
|
|
Number: n, Title: title, Column: col,
|
|
SpecFile: "docs/superpowers/specs/x/spec.md",
|
|
PlanFile: "docs/superpowers/plans/x/plan.md",
|
|
PR: "240", Branch: "feature/abc123",
|
|
}
|
|
}
|
|
var issues []issue.Issue
|
|
issues = append(issues, mk(238, issue.ColumnTodo, "TODOMARK 支持部署时使用客户自定义域名"))
|
|
for i := 0; i < 10; i++ {
|
|
issues = append(issues, mk(220-i, issue.ColumnTodo, "✨ 裂变机制:邀请拉新双向激励(邀请码 + token credit 返利)"))
|
|
}
|
|
issues = append(issues, mk(239, issue.ColumnReview, "REVIEWMARK 分销裂变系统V1"))
|
|
for i := 0; i < 3; i++ {
|
|
issues = append(issues, mk(232-i, issue.ColumnReview, "✨ 实现 Claude Code /rewind 效果:会话与代码/沙箱状态回退"))
|
|
}
|
|
for i := 0; i < 101; i++ {
|
|
issues = append(issues, mk(222-i, issue.ColumnDone, "DONEMARK 用户内容免责协议"))
|
|
}
|
|
|
|
for _, dims := range [][2]int{{250, 55}, {200, 50}, {180, 40}} {
|
|
for _, colIdx := range []int{0, 3} {
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: issues,
|
|
buckets: bucketize(issues),
|
|
width: dims[0],
|
|
height: dims[1],
|
|
colIdx: colIdx,
|
|
}
|
|
out := m.boardView()
|
|
for _, want := range []string{"TODOMARK", "REVIEWMARK", "DONEMARK"} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("dims=%v colIdx=%d: %q missing from boardView", dims, colIdx, want)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|