feat: add read-only CDP target viewing

This commit is contained in:
QiuSW
2026-07-27 10:01:07 +08:00
parent 7816be2a3d
commit 519d3ef636
11 changed files with 668 additions and 18 deletions
+77
View File
@@ -580,6 +580,83 @@ func TestShellIgnoresRefreshResultAfterEditableFieldsChange(t *testing.T) {
}
}
func TestShellReadsTabsAsynchronouslyAndRestoresEditFocus(t *testing.T) {
shell := NewShell(material.NewTheme())
target := shell.rows[0]
seen := make(chan InstanceRow, 1)
shell.OnInspectTabs(func(_ context.Context, row InstanceRow) ([]CDPTarget, error) {
seen <- row
return []CDPTarget{{ID: "page-1", Type: "page", Title: "运营后台", URL: "https://example.com/orders"}}, nil
}, nil)
shell.beginEdit(target.ID)
shell.requestTabs()
if !shell.tabsOpen || !shell.tabsLoading || shell.tabsInstanceID != target.ID {
t.Fatalf("tabs state after request = open %v loading %v instance %q", shell.tabsOpen, shell.tabsLoading, shell.tabsInstanceID)
}
select {
case row := <-seen:
if row.ID != target.ID || row.RemoteDebugPort != target.RemoteDebugPort {
t.Fatalf("tabs snapshot = %#v", row)
}
case <-time.After(time.Second):
t.Fatal("tab inspector was not invoked")
}
var result instanceTabsResult
select {
case result = <-shell.tabsResults:
case <-time.After(time.Second):
t.Fatal("tab inspector did not produce a result")
}
shell.tabsResults <- result
shell.consumeTabsResults()
if shell.tabsLoading || shell.tabsFeedback != "" || len(shell.tabsTargets) != 1 || shell.tabsTargets[0].Title != "运营后台" {
t.Fatalf("tabs result state = loading %v feedback %q targets %#v", shell.tabsLoading, shell.tabsFeedback, shell.tabsTargets)
}
shell.closeTabs(true)
if shell.tabsOpen || !shell.tabsReturnFocus {
t.Fatalf("tabs close state = open %v return focus %v", shell.tabsOpen, shell.tabsReturnFocus)
}
}
func TestShellRejectsStaleTabsResultWhenRuntimeChanges(t *testing.T) {
shell := NewShell(material.NewTheme())
target := shell.rows[0]
shell.OnInspectTabs(func(_ context.Context, _ InstanceRow) ([]CDPTarget, error) {
return []CDPTarget{{ID: "page-1", Type: "page", Title: "运营后台", URL: "https://example.com/orders"}}, nil
}, nil)
shell.beginEdit(target.ID)
shell.requestTabs()
var result instanceTabsResult
select {
case result = <-shell.tabsResults:
case <-time.After(time.Second):
t.Fatal("tab inspector did not produce a result")
}
shell.rows[0].RemoteDebugPort++
shell.tabsResults <- result
shell.consumeTabsResults()
if len(shell.tabsTargets) != 0 || !strings.Contains(shell.tabsFeedback, "状态或调试端口已经变化") {
t.Fatalf("stale tabs result state = targets %#v feedback %q", shell.tabsTargets, shell.tabsFeedback)
}
}
func TestShellAllowsTabInspectionOnlyForVerifiedRuntimeRows(t *testing.T) {
shell := NewShell(material.NewTheme())
if !shell.canInspectTabs(shell.rows[0]) || !shell.canInspectTabs(shell.rows[2]) {
t.Fatal("verified running and external rows should allow read-only tabs inspection")
}
for _, row := range []InstanceRow{
{Status: "启动中", RemoteDebugPort: 9666},
{Status: "已退出", RemoteDebugPort: 9666},
{Status: "运行中", RemoteDebugPort: 0},
} {
if shell.canInspectTabs(row) {
t.Fatalf("row unexpectedly allows tab inspection: %#v", row)
}
}
}
func TestShellEditsExitedInstanceAndPreservesRuntimePort(t *testing.T) {
shell := NewShell(material.NewTheme())
target := shell.rows[3]