From b8ec1e84d244cc0a26d9f9a2793cbbe427b7b6bf Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Wed, 4 Nov 2026 20:23:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(webui):=20=E5=86=8D=E8=BF=81=203=20?= =?UTF-8?q?=E4=B8=AA=E5=88=A4=E6=8D=AE=E5=88=B0=20test/=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E5=8E=BB=E9=87=8D=E8=BE=85=E5=8A=A9=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 迁移 dashboard_js_scope_test.go → webui/test/ embed_read_test.go → webui/test/ mascot_asset_test.go → webui/test/ 这三个原先都直接读未导出的 `dashboardFS`(`go:embed` 的变量)。 上一批已经加了导出入口 `FrontendAsset(name)`,所以只需换调用即可, 不涉及行为改动。 ## 迁移暴露的三处重复(一并去重) 迁过去之后编译报了三组重复定义: stripJSComments helpers_test.go 与 dashboard_js_scope_test.go 各一份 dashboardJSSource helpers_test.go 与 dashboard_js_scope_test.go 各一份 mustReadEmbedded embed_read_test.go 里定义,kernel_buttons_render_test.go 在用 前两个是**迁移造成的镜像**:原本包内的辅助函数在迁到 test/ 时被复制了一份。 逐字比较确认两份 `stripJSComments` 实现完全相同,删掉包内那份、保留 `test/helpers_test.go` 里的共享版本。 第三个不同:`mustReadEmbedded` 只有包内的 `kernel_buttons_render_test.go` 在用。 把它改成直接调导出的 `FrontendAsset`,不再需要这个辅助函数 —— 包内测试从此也不再依赖"哪个变量装着 embed 资源"这种实现细节。 ## 顺带清掉一批未使用导入 批量迁移+脚本改包名之后,多个文件留着已经不用的 `webui` 导入 (有的只在注释里提到 `webui.FrontendAsset`)。用 `go vet` 的输出逐个清理, 最后 `go vet ./internal/plugins/webui/...` 干净。 ## 判据未失效(变异验证) 把 dashboard.js 里 ack 超时 `}, 600000);` 改成 `}, 30000);`: --- FAIL: TestChatAckTimeoutIsGenerous chat_ack_timeout_test.go:59: ★ 受理超时只有 30000 ms —— 太小。 恢复后全绿。 ## 进度 webui/ 180 条(原 186,迁走 6 条) webui/test/ 22 条 合计 202 条,与迁移前一致(+ 之前新增的契约判据) `webui/` 剩下 20 个测试文件,全部依赖 `handleXxx` / `newTestHandler` / `testSDK` 等未导出 handler 与装配辅助,需要先有导出入口才能迁。 其中 `proxy_test.go`(45 处)和 `handler_test.go`(90 处)是最大两块, 要迁必须先给 webui 导出"起一个带路由的 handler"的测试入口。 ## 验证 go build ./... PASS go vet ./internal/plugins/webui/... PASS gofmt -l 干净 go test ./... -count=1 65 包全过,0 FAIL webui 连跑 3 次 0 失败 --- .../webui/kernel_buttons_render_test.go | 6 +- .../{ => test}/dashboard_js_scope_test.go | 73 +------------------ .../webui/{ => test}/embed_read_test.go | 9 ++- internal/plugins/webui/test/helpers_test.go | 3 +- .../webui/{ => test}/mascot_asset_test.go | 5 +- 5 files changed, 18 insertions(+), 78 deletions(-) rename internal/plugins/webui/{ => test}/dashboard_js_scope_test.go (91%) rename internal/plugins/webui/{ => test}/embed_read_test.go (52%) rename internal/plugins/webui/{ => test}/mascot_asset_test.go (97%) diff --git a/internal/plugins/webui/kernel_buttons_render_test.go b/internal/plugins/webui/kernel_buttons_render_test.go index 9529bbb4..0daebabc 100644 --- a/internal/plugins/webui/kernel_buttons_render_test.go +++ b/internal/plugins/webui/kernel_buttons_render_test.go @@ -48,7 +48,11 @@ func TestKernelButtonsRenderedInPage(t *testing.T) { // 判定它处于顶层。jsdom 里的行为测试做不到这点(node 不强求), // 而浏览器里 onclick 走的是全局查找。 func TestKernelFunctionsAreGlobal(t *testing.T) { - src := string(mustReadEmbedded(t, "dashboard.js")) + js, err := FrontendAsset("dashboard.js") + if err != nil { + t.Fatalf("读 dashboard.js: %v", err) + } + src := string(js) for _, fn := range []string{"kernelRestart", "kernelShutdown", "doKernelControl", "waitForKernelBack"} { // 顶层定义:行首(可有 async 前缀),不带缩进 diff --git a/internal/plugins/webui/dashboard_js_scope_test.go b/internal/plugins/webui/test/dashboard_js_scope_test.go similarity index 91% rename from internal/plugins/webui/dashboard_js_scope_test.go rename to internal/plugins/webui/test/dashboard_js_scope_test.go index c2867f19..6f3b5ae4 100644 --- a/internal/plugins/webui/dashboard_js_scope_test.go +++ b/internal/plugins/webui/test/dashboard_js_scope_test.go @@ -1,4 +1,4 @@ -package webui +package test import ( "os" @@ -43,15 +43,7 @@ import ( // 判据做法:用 node 在沙箱里把 dashboard.js 跑一遍,抓未捕获异常。 // node 不在时 t.Skip(CI 里 GO 环境可能没有 node)。 -// dashboardJSSource 取出待测脚本文本(测试内复用以免重复读 embed)。 -func dashboardJSSource(t *testing.T) string { - t.Helper() - b, err := dashboardFS.ReadFile("dashboard.js") - if err != nil { - t.Fatalf("读 dashboard.js: %v", err) - } - return string(b) -} +// dashboardJSSource 见 helpers_test.go(迁移时去重)。 // TestDashboardJS_HasNoReferenceErrorInStrictMode 用 node 跑真脚本抓 ReferenceError。 // @@ -350,63 +342,4 @@ func TestDashboardJS_NoWriteOnlyGlobals(t *testing.T) { } } -func stripJSComments(s string) string { - var b strings.Builder - b.Grow(len(s)) - inLine, inBlock := false, false - var inStr byte - for i := 0; i < len(s); i++ { - c := s[i] - if inLine { - if c == '\n' { - inLine = false - b.WriteByte(c) - } - continue - } - if inBlock { - if c == '*' && i+1 < len(s) && s[i+1] == '/' { - inBlock = false - i++ - } - continue - } - if c == '\n' { - b.WriteByte(c) - continue - } - if inStr != 0 { - b.WriteByte(c) - if c == '\\' { - if i+1 < len(s) { - b.WriteByte(s[i+1]) - i++ - } - continue - } - if c == inStr { - inStr = 0 - } - continue - } - if c == '"' || c == '\'' || c == '`' { - // 反引号也是字符串定界符,但它可跨行 —— 本判据只统计标识符, - // 跨行模板串里出现标识符属正常,此处按普通字符串处理即可。 - inStr = c - b.WriteByte(c) - continue - } - if c == '/' && i+1 < len(s) && s[i+1] == '/' { - inLine = true - i++ - continue - } - if c == '/' && i+1 < len(s) && s[i+1] == '*' { - inBlock = true - i++ - continue - } - b.WriteByte(c) - } - return b.String() -} +// stripJSComments 见 helpers_test.go(迁移时去重)。 diff --git a/internal/plugins/webui/embed_read_test.go b/internal/plugins/webui/test/embed_read_test.go similarity index 52% rename from internal/plugins/webui/embed_read_test.go rename to internal/plugins/webui/test/embed_read_test.go index fb994ca4..e0e203c6 100644 --- a/internal/plugins/webui/embed_read_test.go +++ b/internal/plugins/webui/test/embed_read_test.go @@ -1,10 +1,13 @@ -package webui +package test -import "testing" +import ( + "github.com/JianFeeeee/HologramAgent/internal/plugins/webui" + "testing" +) func mustReadEmbedded(t *testing.T, name string) []byte { t.Helper() - b, err := dashboardFS.ReadFile(name) + b, err := webui.FrontendAsset(name) if err != nil { t.Fatalf("读 embed %s: %v", name, err) } diff --git a/internal/plugins/webui/test/helpers_test.go b/internal/plugins/webui/test/helpers_test.go index 4d9dca16..55e27761 100644 --- a/internal/plugins/webui/test/helpers_test.go +++ b/internal/plugins/webui/test/helpers_test.go @@ -6,10 +6,9 @@ package test // 而在"测试与源码分离"之后,它们不能再从包内符号借用。 import ( + "github.com/JianFeeeee/HologramAgent/internal/plugins/webui" "strings" "testing" - - "github.com/JianFeeeee/HologramAgent/internal/plugins/webui" ) // stripJSComments 剥掉 // 行注释与 /* */ 块注释(粗粒度,但足够用于词频统计)。 diff --git a/internal/plugins/webui/mascot_asset_test.go b/internal/plugins/webui/test/mascot_asset_test.go similarity index 97% rename from internal/plugins/webui/mascot_asset_test.go rename to internal/plugins/webui/test/mascot_asset_test.go index acfbec15..b152b470 100644 --- a/internal/plugins/webui/mascot_asset_test.go +++ b/internal/plugins/webui/test/mascot_asset_test.go @@ -1,9 +1,10 @@ -package webui +package test import ( "bytes" "encoding/binary" "errors" + "github.com/JianFeeeee/HologramAgent/internal/plugins/webui" "testing" ) @@ -21,7 +22,7 @@ import ( // 都在看。所以用容器格式本身来判定:判据看的是 VP8X 的 Alpha 标志位与 // ALPH chunk 是否**一致存在**,而不是「渲染出来像不像透明」。 func TestMascotAssetHasRealAlpha(t *testing.T) { - data, err := dashboardFS.ReadFile("mascot.webp") + data, err := webui.FrontendAsset("mascot.webp") if err != nil { t.Fatalf("读 mascot.webp: %v", err) }