Files
jscriptx/bundle_test.go
what 7c9a70712e 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
挪成外部测试,挪不动。
2026-09-10 15:39:25 +08:00

101 lines
3.0 KiB
Go

package jscriptx_test
import (
"context"
"path/filepath"
"testing"
"git.fsdpf.net/go/jscriptx"
"github.com/evanw/esbuild/pkg/api"
)
// WithBundleDefine:编译期常量替换。
func TestBundleOption_Define(t *testing.T) {
e := newEngine(t, jscriptx.WithBundleOptions(
jscriptx.WithBundleDefine(map[string]string{"__MODE__": `"生产"`}),
))
s := mustCompile(t, e, "def.ts", `
declare const __MODE__: string
export function mode(): string { return __MODE__ }
`)
got, err := s.Call(context.Background(), "mode")
if err != nil {
t.Fatal(err)
}
if got != "生产" {
t.Errorf("常量没被替换, got %#v", got)
}
}
// WithBundleTarget:把语法降级到指定的 ECMAScript 版本。
// goja 对新语法的覆盖不是 100%,调低 target 是遇到问题时的出路。
func TestBundleOption_Target(t *testing.T) {
// 用可选链和空值合并这类较新的语法,降级到 ES2015 后应该被改写掉
src := `export function pick(o) { return o?.a?.b ?? "兜底" }`
for _, target := range []struct {
name string
t api.Target
}{{"ES2015", api.ES2015}, {"ES2020", api.ES2020}} {
t.Run(target.name, func(t *testing.T) {
e := newEngine(t, jscriptx.WithBundleOptions(jscriptx.WithBundleTarget(target.t)))
s := mustCompile(t, e, "t.ts", src)
ctx := context.Background()
got, err := s.Call(ctx, "pick", map[string]any{"a": map[string]any{"b": "命中"}})
if err != nil {
t.Fatalf("调用失败: %v", err)
}
if got != "命中" {
t.Errorf("got = %#v", got)
}
if got, err := s.Call(ctx, "pick", nil); err != nil || got != "兜底" {
t.Errorf("空值合并没生效: got=%#v err=%v", got, err)
}
})
}
}
// WithNodePaths / WithAlias:给直接 Compile 的源码指定模块来源。
func TestBundleOption_NodePathsAndAlias(t *testing.T) {
libs, err := filepath.Abs("esm/testdata/app/node_modules")
if err != nil {
t.Fatal(err)
}
src := `import { upper } from "tinylib"
export function shout(s: string): string { return upper(s) }`
// 不指定时找不到:这段源码没有文件系统上下文
e0 := newEngine(t)
if _, err := e0.Compile("x.ts", src); err == nil {
t.Error("没有解析基准时应该报错")
}
// NodePaths 指向 node_modules 所在目录
e1 := newEngine(t, jscriptx.WithBundleOptions(jscriptx.WithNodePaths(libs)))
s1, err := e1.Compile("x.ts", src)
if err != nil {
t.Fatalf("WithNodePaths 没生效: %v", err)
}
if got, _ := s1.Call(context.Background(), "shout", "hi"); got != "HI" {
t.Errorf("got = %#v", got)
}
// Alias 把模块名钉到具体文件
impl, err := filepath.Abs("esm/testdata/app/node_modules/tinylib/index.js")
if err != nil {
t.Fatal(err)
}
e2 := newEngine(t, jscriptx.WithBundleOptions(
jscriptx.WithAlias(map[string]string{"tinylib": impl}),
))
s2, err := e2.Compile("x.ts", src)
if err != nil {
t.Fatalf("WithAlias 没生效: %v", err)
}
if got, _ := s2.Call(context.Background(), "shout", "hi"); got != "HI" {
t.Errorf("got = %#v", got)
}
}