Files
HomeAgent/internal/plugins/webui/test/kernel_buttons_render_test.go
JianFeeeee 790a28fdfd fix(webui): 补提交 kernel_buttons 判据的 package/import 改动
## 事故:上一个 commit 只提交了 rename,没提交内容改动

`fb67703` 用 `git mv` 把 `kernel_buttons_render_test.go` 移进 `test/`,
但改 `package webui → package test`、`dashboardHTML → webui.DashboardPage()`
这些编辑留在工作区没进暂存区。结果 **HEAD 的 `test/` 目录里放着一个
`package webui` 的文件**:

    found packages test (chat_ack_timeout_test.go) and webui
      (kernel_buttons_render_test.go) in internal/plugins/webui/test

本仓 `.gitignore` 忽略 `build/`,本地 `go test ./...` 也过了 —— 但那是
**带未提交改动的工作区**过了,不是这个 commit 过了。干净 worktree 复验:

    git worktree add /tmp/cleanchk HEAD
    go test ./internal/plugins/webui/test/
    → FAIL [setup failed] found packages test and webui

这正是 2026-11-03 定的提交纪律第 5 条要拦的事。上一批做完 `git mv`
只 `git diff --cached --stat` 看到 "0 insertions" 就该警觉 —— rename 的
staged diff 是 0,而内容改动是 unstaged,等于提交了个半成品。

## 教训(写进流程)

`git mv` 之后**必须再 `git add` 一次同名路径**,否则只提交移动本身。
以后每批提交前一律:

    git diff --stat                    # 看 unstaged 是否还有内容
    git worktree add /tmp/clean <sha> # 干净检出复验
    go build ./... && go test ./...

## 本提交的改动

    package webui → package test
    dashboardHTML → webui.DashboardPage()
    FrontendAsset → webui.FrontendAsset
    import 补 internal/plugins/webui + gofmt 排序

## 验证

干净 worktree(本提交后)复验通过,见下一条命令的输出。
2026-11-09 09:58:14 +08:00

89 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package test
// 内核按钮必须**真的出现在渲染后的页面里**(2026-10-17)。
//
// ## 为什么这条判据必须存在
//
// dashboard.html 与 dashboard.js 都是 `//go:embed` 进二进制的,然后由
// init 组装成 dashboardHTML(把 {{DASHBOARD_JS}} 等占位符替换成实际内容)。
// 这里有两个**各自都可能坏掉**的环节:
//
// 1. 按钮写进了 dashboard.html,但占位符没被替换/替换错位
// ⇒ 页面里看不到按钮
// 2. JS 函数写进了 dashboard.js,但它被包在 IIFE 里(不在全局)
// ⇒ onclick="kernelRestart()" 点了报 "kernelRestart is not defined"
//
// 只查源码有没有那个字符串,这两种情况都照不出来。
// 所以判据查的是**组装后的 dashboardHTML**(就是实际发给浏览器的字节)。
import (
"github.com/JianFeeeee/HologramAgent/internal/plugins/webui"
"strings"
"testing"
)
// ★★★ 判据:渲染后的页面含两个按钮的 id 与 onclick。
func TestKernelButtonsRenderedInPage(t *testing.T) {
h := webui.DashboardPage()
if h == "" {
t.Fatal("dashboardHTML 为空 —— init 没跑或 embed 失败")
}
for _, want := range []struct {
what string
s string
}{
{"重启按钮 id", `id="kernel-restart-btn"`},
{"关机按钮 id", `id="kernel-shutdown-btn"`},
{"重启按钮 onclick", `onclick="kernelRestart()"`},
{"关机按钮 onclick", `onclick="kernelShutdown()"`},
} {
if !strings.Contains(h, want.s) {
t.Fatalf("★ 渲染页面缺少%s(%q)—— 用户在界面上看不到它", want.what, want.s)
}
}
}
// ★★★ 判据:JS 函数必须在**全局作用域**(onclick 才找得到)。
//
// 检查方式:函数定义前不能有包裹它的 IIFE 缩进层级 —— 用"行首即 function"
// 判定它处于顶层。jsdom 里的行为测试做不到这点(node 不强求),
// 而浏览器里 onclick 走的是全局查找。
func TestKernelFunctionsAreGlobal(t *testing.T) {
js, err := webui.FrontendAsset("dashboard.js")
if err != nil {
t.Fatalf("读 dashboard.js: %v", err)
}
src := string(js)
for _, fn := range []string{"kernelRestart", "kernelShutdown", "doKernelControl", "waitForKernelBack"} {
// 顶层定义:行首(可有 async 前缀),不带缩进
if !strings.Contains(src, "\nasync function "+fn+"(") &&
!strings.Contains(src, "\nfunction "+fn+"(") {
t.Fatalf("★ %s 不是顶层函数定义 —— "+
"若它被包在 IIFE/模块里,按钮 onclick 会报 is not defined", fn)
}
}
}
// ★★★ 判据:两个按钮都必须在 nav-footer 里(不是被误放到某个标签页内)。
//
// 它们作用于整个服务,任何标签页都该能点到。
func TestKernelButtonsInNavFooter(t *testing.T) {
h := webui.DashboardPage()
navIdx := strings.Index(h, `class="nav-footer"`)
if navIdx < 0 {
t.Fatal("找不到 nav-footer")
}
navEnd := strings.Index(h[navIdx:], "</nav>")
if navEnd < 0 {
t.Fatal("找不到 nav 结束标签")
}
footer := h[navIdx : navIdx+navEnd]
for _, id := range []string{"kernel-restart-btn", "kernel-shutdown-btn"} {
if !strings.Contains(footer, id) {
t.Fatalf("★ %s 不在 nav-footer 内 —— 用户切到别的标签页就找不到它了", id)
}
}
}