Files
MujicaUI/project/pomodoro_timer_test.go
T

135 lines
3.5 KiB
Go

package project
import (
"testing"
"time"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/core"
)
type pomodoroProbe struct {
s PomodoroState
now time.Time
opts PomodoroTimerOptions
finished []PomodoroPhase
changes int
}
func (p *pomodoroProbe) tester() *ui.Tester {
p.now = time.Date(2026, time.October, 5, 9, 0, 0, 0, time.UTC)
return ui.NewTester(func(c *ui.Context) {
core.Use(c, core.Settings{})
o := p.opts
o.Now = p.now
r := PomodoroTimer(c, &p.s, o)
if ph, ok := r.Finished(); ok {
p.finished = append(p.finished, ph)
}
if r.Changed() {
p.changes++
}
}, 400, 400)
}
func TestPomodoroTimerCycle(t *testing.T) {
p := &pomodoroProbe{opts: PomodoroTimerOptions{Focus: 2 * time.Second, Break: time.Second, LongBreak: 3 * time.Second, LongEvery: 2}}
tt := p.tester()
if !tt.HasText("Focus, 2 s left") {
t.Fatalf("start %v", tt.Texts())
}
_ = tt.Click("Start")
p.now = p.now.Add(900 * time.Millisecond)
tt.Frame()
if !tt.HasText("Focus, 2 s left") {
t.Fatal("seconds round up")
}
_ = tt.Click("Pause")
p.now = p.now.Add(time.Hour)
tt.Frame()
if !tt.HasText("Focus, 2 s left") || p.s.Running() {
t.Fatal("pause should hold the clock")
}
_ = tt.Click("Start")
p.now = p.now.Add(1100 * time.Millisecond)
tt.Frame()
if len(p.finished) != 1 || p.finished[0] != PomodoroFocus || p.s.Phase() != PomodoroBreak || p.s.Running() || p.s.Sessions() != 1 {
t.Fatalf("focus end: %v %v", p.finished, p.s.Phase())
}
if a := tt.Announcements(); len(a) == 0 || a[len(a)-1] != "Focus finished." {
t.Fatalf("announce %q", a)
}
_ = tt.Click("Skip")
_ = tt.Click("Skip")
if p.s.Phase() != PomodoroLongBreak || p.s.Sessions() != 2 {
t.Fatalf("second focus should earn a long break: %v", p.s.Phase())
}
_ = tt.Click("Reset")
if p.s.Phase() != PomodoroFocus || p.s.Sessions() != 0 || p.changes != 6 {
t.Fatalf("reset %v (%d)", p.s.Phase(), p.changes)
}
}
func TestPomodoroTimerKeyboardDisabledInvalid(t *testing.T) {
p := &pomodoroProbe{opts: PomodoroTimerOptions{Disabled: true}}
tt := p.tester()
_ = tt.Click("Start")
tt.Key(0, ui.KeyTab)
tt.Key(0, ui.KeyEnter)
if p.s.Running() || p.changes != 0 || !tt.HasText("Focus, 25 min left") {
t.Fatal("disabled timer started")
}
q := &pomodoroProbe{}
tt = q.tester()
tt.Key(0, ui.KeyTab)
tt.Key(0, ui.KeyEnter)
if !q.s.Running() {
t.Fatal("Enter should start")
}
defer func() {
if recover() == nil {
t.Fatal("expected panic")
}
}()
bad := &pomodoroProbe{opts: PomodoroTimerOptions{Focus: 1500 * time.Millisecond}}
bad.tester()
}
func TestPomodoroTimerSnapshot(t *testing.T) {
now := time.Date(2026, time.October, 5, 9, 0, 0, 0, time.UTC)
s := PomodoroState{spent: 10 * time.Minute}
snapshot(t, "pomodoro_timer", 360, 300, func(c *ui.Context) {
ui.Column(c).Padding(16).Children(func() { PomodoroTimer(c, &s, PomodoroTimerOptions{Now: now}) })
})
}
func TestPomodoroTimerIdleAndHidden(t *testing.T) {
s, shown, builds := PomodoroState{}, true, 0
tt := ui.NewTester(func(c *ui.Context) {
builds++
core.Use(c, core.Settings{})
if shown {
PomodoroTimer(c, &s, PomodoroTimerOptions{})
}
}, 400, 400)
if builds > 2 {
t.Fatalf("idle built %d frames", builds)
}
if err := tt.Click("Start"); err != nil {
t.Fatal(err)
}
shown = false
tt.Frame()
before := builds
time.Sleep(1100 * time.Millisecond)
if builds != before || !s.Running() {
t.Fatalf("hidden timer: builds %d, running %v", builds, s.Running())
}
shown = true
tt.Frame()
if !tt.HasText("Pause") {
t.Fatal("visible timer did not retain its clock")
}
}