Files
cdp_hub/internal/ui/shell_test.go
T

167 lines
5.4 KiB
Go

package ui
import (
"context"
"testing"
"time"
"gioui.org/widget/material"
)
func TestShellStartsWithSemanticInstanceStatuses(t *testing.T) {
shell := NewShell(material.NewTheme())
seen := map[string]bool{}
for _, row := range shell.rows {
seen[row.Status] = true
}
for _, status := range []string{"运行中", "启动中", "外部占用", "已退出"} {
if !seen[status] {
t.Fatalf("status %q is missing", status)
}
}
}
func TestShellInstanceRowsContainRequiredColumnsAndIndependentStartControls(t *testing.T) {
shell := NewShell(material.NewTheme())
if len(shell.rows) < 2 {
t.Fatal("expected fixture rows")
}
for _, row := range shell.rows {
if row.ID == "" || row.Name == "" || row.Browser == "" || row.UserDataDir == "" || row.Status == "" {
t.Fatalf("incomplete instance row: %#v", row)
}
}
first := shell.startClickFor(shell.rows[0].ID)
second := shell.startClickFor(shell.rows[1].ID)
if first == second {
t.Fatal("rows share a start button state")
}
}
func TestInstanceListColumnWeightsPrioritizeDirectoryAndCompactAction(t *testing.T) {
got := instanceNameColumnWeight + instanceBrowserColumnWeight + instanceDirectoryColumnWeight + instanceStatusColumnWeight + instanceStartColumnWeight
if got != 100 {
t.Fatalf("instance column weights = %d, want 100", got)
}
if instanceDirectoryColumnWeight <= instanceNameColumnWeight {
t.Fatal("user data directory must have the widest instance-list column")
}
if instanceStartColumnWeight >= instanceStatusColumnWeight {
t.Fatal("start action column must remain compact")
}
}
func TestShellCancelsOnlyTheActivePathSearch(t *testing.T) {
shell := NewShell(material.NewTheme())
started := make(chan struct{}, 1)
shell.OnPathSearch(func(ctx context.Context, field PathField, current string) (string, error) {
started <- struct{}{}
<-ctx.Done()
return "", ctx.Err()
}, nil)
shell.togglePathSearch(PathChromeExecutable)
if got := shell.searchButtonLabel(PathChromeExecutable); got != "取消" {
t.Fatalf("chrome search label = %q, want 取消", got)
}
if got := shell.searchButtonLabel(PathEdgeExecutable); got != "搜索" {
t.Fatalf("edge search label = %q, want 搜索", got)
}
select {
case <-started:
case <-time.After(time.Second):
t.Fatal("search did not start")
}
shell.togglePathSearch(PathChromeExecutable)
if got := shell.searchButtonLabel(PathChromeExecutable); got != "搜索" {
t.Fatalf("chrome search label = %q after cancel, want 搜索", got)
}
}
func TestShellAppliesLatestPathSearchResult(t *testing.T) {
shell := NewShell(material.NewTheme())
shell.OnPathSearch(func(context.Context, PathField, string) (string, error) {
return `C:\Browser\chrome.exe`, nil
}, nil)
shell.togglePathSearch(PathChromeExecutable)
var result pathSearchResult
select {
case result = <-shell.searchResults:
case <-time.After(time.Second):
t.Fatal("search did not produce a result")
}
shell.searchResults <- result
shell.consumeSearchResults()
if got := shell.chromePath.Text(); got != `C:\Browser\chrome.exe` {
t.Fatalf("chrome path = %q", got)
}
}
func TestShellSettingsCanBeRestored(t *testing.T) {
shell := NewShell(material.NewTheme())
shell.SetSettings(SettingsState{ChromePath: "chrome", EdgePath: "edge", DefaultDir: "profiles", LogDir: "logs", CloseOnExit: false})
if shell.chromePath.Text() != "chrome" || shell.edgePath.Text() != "edge" || shell.dataDir.Text() != "profiles" || shell.logDir.Text() != "logs" || shell.closeOnExit.Value {
t.Fatalf("settings were not restored")
}
}
func TestShellKeepsSettingsStateAcrossPageSwitch(t *testing.T) {
shell := NewShell(material.NewTheme())
shell.page = pageSettings
shell.dataDir.SetText(`D:\profiles\current`)
shell.pathFeedback = "正在搜索默认 User Data Dir…"
shell.page = pageInstances
shell.page = pageSettings
if got := shell.dataDir.Text(); got != `D:\profiles\current` {
t.Fatalf("data dir = %q", got)
}
if got := shell.pathFeedback; got != "正在搜索默认 User Data Dir…" {
t.Fatalf("path feedback = %q", got)
}
}
func TestShellIgnoresCancelledPathSearchResult(t *testing.T) {
shell := NewShell(material.NewTheme())
started := make(chan struct{}, 1)
shell.OnPathSearch(func(ctx context.Context, field PathField, current string) (string, error) {
started <- struct{}{}
<-ctx.Done()
return `C:\stale\chrome.exe`, nil
}, nil)
shell.togglePathSearch(PathChromeExecutable)
select {
case <-started:
case <-time.After(time.Second):
t.Fatal("search did not start")
}
shell.togglePathSearch(PathChromeExecutable)
select {
case result := <-shell.searchResults:
shell.searchResults <- result
case <-time.After(time.Second):
t.Fatal("cancelled search did not return")
}
shell.consumeSearchResults()
if got := shell.chromePath.Text(); got == `C:\stale\chrome.exe` {
t.Fatal("cancelled result overwrote the editor")
}
}
func TestShellAppliesSelectedInstanceDirectory(t *testing.T) {
shell := NewShell(material.NewTheme())
shell.OnChooseDirectory(func(context.Context) (string, error) {
return `C:\profiles\new-instance`, nil
}, nil)
shell.chooseInstanceDirectory()
var result directoryPickResult
select {
case result = <-shell.directoryResults:
case <-time.After(time.Second):
t.Fatal("directory picker did not produce a result")
}
shell.directoryResults <- result
shell.consumeDirectoryResults()
if got := shell.instanceDir.Text(); got != `C:\profiles\new-instance` {
t.Fatalf("instance dir = %q", got)
}
}