go webassembly 测试必须用 go test + wasmexec 启动 js 沙箱环境,因无 os 进程、标准 i/o 和文件系统,需通过 wasmexec 提供的微型浏览器环境执行测试;t.parallel() 无效、t.tempdir() 返回空、log 输出仅见于浏览器 console;js 交互函数应拆分纯 go 逻辑单独测试;ci 中应使用 headless chrome 替代 wasmexec 以保障稳定性与日志捕获。

Go WebAssembly 测试必须用 go test + wasmexec 启动环境
Go 编译成 WebAssembly 后,代码运行在 JS 沙箱里,没法直接用常规 go test 执行。核心限制是:没有 OS 进程、无标准输入输出、os.Exit 会 panic,log 输出不显示在终端。所以测试脚本本质是「启动一个微型浏览器环境,加载 wasm + JS glue,再触发 Go 测试函数」。
Go 自带的 wasmexec 就是干这事的——它是个小型 HTTP 服务器 + HTML 模板,把 test.wasm 塞进页面并调用 runTests()。你不需要自己写 HTML 或 JS 胶水代码。
- 确保用
GOOS=js GOARCH=wasm go test -c -o test.wasm生成可执行 wasm 文件(不是build) - 必须从 Go 安装目录复制
wasm_exec.js到当前目录:cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . - 运行测试命令:
$(go env GOROOT)/misc/wasm/wasmexec ./test.wasm,它会自动开 localhost:8080 并跑完退出 - 如果看到
exit status 1但没报错信息,大概率是wasm_exec.js路径不对或没同目录
testing.T 在 wasm 中的行为和陷阱
Go 的测试框架在 wasm 下能用,但部分行为被降级或禁用。最常踩的坑是依赖时间、文件系统或并发控制。
-
t.Parallel()无效:wasm 是单线程,调用后测试不会并行,也不会报错,但会拖慢整体执行(因为等待不存在的 goroutine 调度) -
t.TempDir()返回空字符串且不创建目录——wasm 没有文件系统,所有基于os的操作都会静默失败或 panic -
t.Log()和t.Error()输出会写入浏览器 console,但只有在wasmexec启动的页面里才能看到;本地终端看不到 - 超时控制靠
go test -timeout=30s,不是t.Cleanup或time.AfterFunc——后者在 wasm 里可能根本不会触发
如何测带 syscall/js 交互的函数
如果你的 wasm 模块暴露了 JS 可调用函数(比如用 syscall/js.FuncOf 注册),测试时不能只靠 go test 内部逻辑,得模拟 JS 端调用链。
立即学习“go语言免费学习笔记(深入)”;
- 不要在测试函数里直接调用
js.Global().Call(...)——js.Global()在go test模式下是 nil,会 panic - 正确做法:把业务逻辑拆成纯 Go 函数(无
syscall/js依赖),单独测试;JS 胶水层只做参数转发,用最小化 HTML + 手动打开 DevTools 验证 - 若真要端到端测 JS 调用,得写一个临时 HTML:
<script src="wasm_exec.js"></script><script>const go = new Go(); WebAssembly.instantiateStreaming(fetch("test.wasm"), go.importObject).then(...)</script>,然后在 console 里手动调用 - 注意:测试中用
js.Value类型的参数必须来自js.Global()或真实 JS 上下文,不能 mock——Go 的reflect无法构造合法js.Value
CI 里跑 wasm 测试要用 chromium-headless 替代 wasmexec
wasmexec 是开发辅助工具,不是稳定测试载体。它不支持 exit code 透出、日志捕获困难、无法集成覆盖率,CI 里直接用会卡住流水线。
- 推荐方案:用
chromium --headless --remote-debugging-port=9222启动浏览器,再用curl或轻量 client 访问测试页面并抓取 console 输出 - 更稳的做法是用
go-wasm-test-runner这类第三方工具(如github.com/agnivade/go-wasm-test-runner),它封装了 headless Chrome 启动、日志提取、超时控制 - 关键点:wasm 测试的
main函数必须调用os.Exit(0)或runtime.Goexit()显式结束,否则 headless 浏览器不会关进程,CI 无限挂起 - 覆盖率目前无法直接生成
html报告——go tool cover不支持 wasm,只能靠单元逻辑覆盖 + JS 层断言补全
真正难的不是跑起来,而是区分清楚哪些逻辑该在 Go 层测、哪些必须拉 JS 环境进来;边界模糊的地方,往往一跑就黑屏或静默失败。










