Skip to content

Commit

Permalink
Make setTimeout and co. globally available by default
Browse files Browse the repository at this point in the history
closes #3589
  • Loading branch information
mstoykov committed Apr 23, 2024
1 parent cca18f2 commit ff775f9
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 4 deletions.
1 change: 1 addition & 0 deletions js/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ func (b *Bundle) instantiate(vuImpl *moduleVUImpl, vuID uint64) (*goja.Object, e

modSys := modules.NewModuleSystem(b.ModuleResolver, vuImpl)
b.setInitGlobals(rt, vuImpl, modSys)
modules.ExportGloballyModule(rt, modSys, "k6/timers")
vuImpl.initEnv = initenv
defer func() {
vuImpl.initEnv = nil
Expand Down
37 changes: 37 additions & 0 deletions js/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -925,3 +925,40 @@ func TestBundleMakeArchive(t *testing.T) {
})
}
}

func TestGlobalTimers(t *testing.T) {
t.Parallel()
data := `
import timers from "k6/timers";
if (setTimeout != timers.setTimeout) {
throw "setTimeout doesn't match";
}
if (clearTimeout != timers.clearTimeout) {
throw "clearTimeout doesn't match";
}
if (setInterval != timers.setInterval) {
throw "setInterval doesn't match";
}
if (clearInterval != timers.clearInterval) {
throw "clearInterval doesn't match";
}
export default function() {}
`

b1, err := getSimpleBundle(t, "/script.js", data)
require.NoError(t, err)
logger := testutils.NewLogger(t)

b2, err := NewBundleFromArchive(getTestPreInitState(t, logger, nil), b1.makeArchive())
require.NoError(t, err)

bundles := map[string]*Bundle{"Source": b1, "Archive": b2}
for name, b := range bundles {
b := b
t.Run(name, func(t *testing.T) {
t.Parallel()
_, err := b.Instantiate(context.Background(), 1)
require.NoError(t, err)
})
}
}
10 changes: 6 additions & 4 deletions js/modules/k6/timers/timers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ func (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {
func (e *Timers) Exports() modules.Exports {
return modules.Exports{
Named: map[string]interface{}{
"setTimeout": e.setTimeout,
"clearTimeout": e.clearTimeout,
"setInterval": e.setInterval,
"clearInterval": e.clearInterval,
// TODO the usage of `ToValue` here is so that goja doesn't do it automatically later
// which will effectively create new instance each time it is accessed.
"setTimeout": e.vu.Runtime().ToValue(e.setTimeout),
"clearTimeout": e.vu.Runtime().ToValue(e.clearTimeout),
"setInterval": e.vu.Runtime().ToValue(e.setInterval),
"clearInterval": e.vu.Runtime().ToValue(e.clearInterval),
},
}
}
Expand Down
12 changes: 12 additions & 0 deletions js/modules/resolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,15 @@ func (ms *ModuleSystem) RunSourceData(source *loader.SourceData) (goja.Value, er
}
return ms.Require(pwd, specifier)
}

// ExportGloballyModule sets all exports of the provided module name on the globalThis.
// effectively making them globally available
func ExportGloballyModule(rt *goja.Runtime, modSys *ModuleSystem, moduleName string) {
t, _ := modSys.Require(nil, moduleName)

for _, key := range t.Keys() {
if err := rt.Set(key, t.Get(key)); err != nil {
panic(fmt.Errorf("failed to set '%s' global object: %w", key, err))
}
}
}

0 comments on commit ff775f9

Please sign in to comment.