test: 测试文件跟源文件同名,删掉复制粘贴出来的重复
改完之后「某个行为在哪测」就是查同名文件:
lazyglobal_test.go → engine_globals_test.go
static_test.go → script_static_test.go
scope_pool_test.go → script_vm_test.go 它测的是 VM 池,不是作用域
esmwrap_test.go → bundle_finalize_test.go
missing_global_test.go → errors_hints_test.go
entry_test.go → bundle_entry_test.go 并收下 bundle_test.go 里
那三个 TestEntry_*
删掉 5 组复制粘贴。其中 TestNew_同实例调用串行 和 TestInstance_调用串行 **函数体
完全一致**,只差 mustCompile 的文件名参数 counter.js / counter.ts。Instance 的
测试全部归 instance_test.go 并统一前缀成 TestInstance_,scope_test.go 只留作用域。
vmstate_test.go + govalue_test.go → goja_facts_test.go。这两个测的都是 **goja
本身**,不是这个库:Program 能不能给多个 Runtime 共用、顶层变量跟不跟 Runtime 走、
Go 的切片进到脚本里是不是真数组。它们是「为什么这个库要这么设计」的实验记录,
goja 行为变了会先红。原来那个名字看不出这层定位。
helper 集中到 helper_test.go:newEngine / mustCompile 被十几个文件依赖,原来住在
script_test.go 里,那个名字暗示「测 Script」,找不到。
caller_example_test.go 并进 caller_test.go——同一个类型没必要两个文件。
overlay_test.go 和 script_vm_test.go 保持内部测试,各写了一句为什么:前者要读
Engine.loader 和 isPrepared,后者要直接断言 vmHandle.scoped。我试过把 overlay
挪成外部测试,挪不动。
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package jscriptx_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.fsdpf.net/go/jscriptx"
|
||||
)
|
||||
|
||||
// 脚本碰到 goja 没有的全局时,光一句 ReferenceError 会把人带偏——
|
||||
// 外部作者看到 "setTimeout is not defined" 会以为是打包漏了依赖,跑去装 polyfill。
|
||||
// 这组用例守着那句补充说明。
|
||||
func TestMissingGlobal_报错带上人话(t *testing.T) {
|
||||
cases := []struct {
|
||||
代码 string
|
||||
要点 []string
|
||||
}{
|
||||
{`setTimeout(() => {}, 10)`, []string{"没有事件循环", "Job / Cron"}},
|
||||
{`clearInterval(1)`, []string{"定时器用不了"}},
|
||||
{`structuredClone({})`, []string{"JSON.parse", "深拷贝"}},
|
||||
{`const 名 = "lodash"; require(名)`, []string{"ES 模块", "import"}}, // 动态名字,esbuild 打包期解析不了,才会漏到运行期
|
||||
{`process.env.X`, []string{"不跑在 Node"}},
|
||||
{`document.body`, []string{"没有 DOM"}},
|
||||
{`fetch("http://x")`, []string{"同步执行", "Go 侧"}},
|
||||
}
|
||||
|
||||
e, err := jscriptx.New(jscriptx.WithLogger(nil))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
|
||||
for _, c := range cases {
|
||||
s, err := e.Compile("m.ts", "export default class C { Run() { "+c.代码+" } }")
|
||||
if err != nil {
|
||||
t.Fatalf("%s 编译失败: %v", c.代码, err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
obj, err := s.New(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("%s 实例化失败: %v", c.代码, err)
|
||||
}
|
||||
_, err = obj.Call(ctx, "Run")
|
||||
obj.Close()
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("%s 该报错", c.代码)
|
||||
continue
|
||||
}
|
||||
for _, want := range c.要点 {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("%s 的错误里该提到 %q\n实际: %v", c.代码, want, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 只认 goja 原样的那句,别把脚本自己抛的同名字符串也当成缺全局。
|
||||
func TestMissingGlobal_不误伤(t *testing.T) {
|
||||
e, err := jscriptx.New(jscriptx.WithLogger(nil))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
|
||||
s, err := e.Compile("m.ts", `
|
||||
export default class C {
|
||||
Run() { throw new Error("ReferenceError: setTimeout is not defined") }
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
obj, _ := s.New(ctx)
|
||||
defer obj.Close()
|
||||
|
||||
_, err = obj.Call(ctx, "Run")
|
||||
if err == nil {
|
||||
t.Fatal("该报错")
|
||||
}
|
||||
// 脚本自己抛的,goja 会加上 "Error: " 前缀,前缀对不上就不该补提示
|
||||
if strings.Contains(err.Error(), "没有事件循环") {
|
||||
t.Errorf("不该给脚本自己抛的异常补提示: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 定义成"一调就报错"的桩会破坏特性探测,所以这些全局必须保持 undefined。
|
||||
func TestMissingGlobal_特性探测仍然可用(t *testing.T) {
|
||||
e, err := jscriptx.New(jscriptx.WithLogger(nil))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
|
||||
s, err := e.Compile("m.ts", `
|
||||
export default class C {
|
||||
Run() {
|
||||
// 库里常见的降级写法
|
||||
return typeof setTimeout === "undefined" ? "走降级分支" : "走定时器分支"
|
||||
}
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
obj, _ := s.New(ctx)
|
||||
defer obj.Close()
|
||||
|
||||
got, err := obj.Call(ctx, "Run")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "走降级分支" {
|
||||
t.Errorf("定时器该是 undefined,好让库能降级,拿到 %#v", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user