Skip to content

Commit 74399db

Browse files
author
RoFlection Bot
committed
Fix test runtime regression due to loadstring fallback check (#455)
## Problem seeing a ~10% slowdown in large test suites, likely due to the loadModuleEnabled check that runs once per file and does a ton of pcalls and instance creation ``` - SocialCommon .................. succeeded (4.79 min) - SocialCommon-fastFlags-allOn .. succeeded (4.88 min) Total time: 4.88 min ``` ``` - SocialCommon .................. succeeded (4.56 min) - SocialCommon-fastFlags-allOn .. succeeded (4.59 min) Total time: 4.59 min ``` ## Solution turn it into a const ## Testing loadstring fallback should work as usual and pass the low privilege test suite, seeing an improvement in test runtime in lua-apps ## Checklist ### For all changes - [ ] Describe this change in `CHANGELOG.md` - [ ] [Open a PR to add/update relevant examples in jest-demo](https://github.com/Roblox/jest-demo) ### When working with upstream code (remove if not applicable) - [ ] Newly translated modules have a `README.md` file with notes about the translation - [ ] All deviations are notated in code with `-- ROBLOX deviation: comment` - [ ] Translated files include a comment with a link to the upstream file
1 parent 72aa2d9 commit 74399db

File tree

2 files changed

+6
-97
lines changed

2 files changed

+6
-97
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* :hammer_and_wrench: Rojo + Luau LSP is the new default workflow for Jest
66
development ([#453](https://github.com/Roblox/jest-roblox-internal/pull/453))
7+
* :bug: Fix test runtime regression due to loadstring fallback check ([#455](https://github.com/Roblox/jest-roblox-internal/pull/455))
78

89
## 3.13.2 (2025-05-07)
910
* :bug: Correctly pass in `path` property of `test` in the `onTestCaseResult` reporter hook ([#450](https://github.com/Roblox/jest-roblox-internal/pull/450))

src/jest-runtime/src/init.lua

Lines changed: 5 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -6,98 +6,18 @@
66
* This source code is licensed under the MIT license found in the
77
* LICENSE file in the root directory of this source tree.
88
]]
9-
-- ROBLOX deviation START: skipped
10-
-- type void = nil --[[ ROBLOX FIXME: adding `void` type alias to make it easier to use Luau `void` equivalent when supported ]]
11-
-- ROBLOX deviation END
129
local Packages = script.Parent
1310
local LuauPolyfill = require(Packages.LuauPolyfill)
14-
-- ROBLOX deviation START: skipped
15-
-- local Array = LuauPolyfill.Array
16-
-- ROBLOX deviation END
1711
local Boolean = LuauPolyfill.Boolean
1812
local Error = LuauPolyfill.Error
1913
local Map = LuauPolyfill.Map
2014
local Object = LuauPolyfill.Object
21-
-- ROBLOX deviation START: skipped
22-
-- local Set = LuauPolyfill.Set
23-
-- local WeakMap = LuauPolyfill.WeakMap
24-
-- local console = LuauPolyfill.console
25-
-- local instanceof = LuauPolyfill.instanceof
26-
-- ROBLOX deviation END
2715
type Array<T> = LuauPolyfill.Array<T>
28-
-- ROBLOX deviation START: skipped
29-
-- type Error = LuauPolyfill.Error
30-
-- ROBLOX deviation END
3116
type Map<T, U> = LuauPolyfill.Map<T, U>
3217
type Promise<T> = LuauPolyfill.Promise<T>
33-
-- ROBLOX deviation START: skipped
34-
-- type Set<T> = LuauPolyfill.Set<T>
35-
-- type WeakMap<T, U> = LuauPolyfill.WeakMap<T, U>
36-
-- ROBLOX deviation END
3718
type Omit<T, K> = T --[[ ROBLOX TODO: TS 'Omit' built-in type is not available in Luau ]]
38-
-- ROBLOX deviation START: skipped
39-
-- type Parameters<T> = any --[[ ROBLOX TODO: TS 'Parameters' built-in type is not available in Luau ]]
40-
-- local Promise = require(Packages.Promise)
41-
-- local exports = {}
42-
-- local nativeModule = require(Packages.module)
43-
-- local path = require(Packages.path)
44-
-- local urlModule = require(Packages.url)
45-
-- local URL = urlModule.URL
46-
-- local fileURLToPath = urlModule.fileURLToPath
47-
-- local pathToFileURL = urlModule.pathToFileURL
48-
-- local vmModule = require(Packages.vm)
49-
-- local Script = vmModule.Script
50-
-- -- @ts-expect-error: experimental, not added to the types
51-
-- local SourceTextModule = vmModule.SourceTextModule
52-
-- -- @ts-expect-error: experimental, not added to the types
53-
-- local SyntheticModule = vmModule.SyntheticModule
54-
-- local VMContext = vmModule.Context
55-
-- -- @ts-expect-error: experimental, not added to the types
56-
-- local VMModule = vmModule.Module
57-
-- local parseCjs = require(Packages["cjs-module-lexer"]).parse
58-
-- local collectV8CoverageModule = require(Packages["collect-v8-coverage"])
59-
-- local CoverageInstrumenter = collectV8CoverageModule.CoverageInstrumenter
60-
-- local V8Coverage = collectV8CoverageModule.V8Coverage
61-
-- local execa = require(Packages.execa)
62-
-- local fs = require(Packages["graceful-fs"])
63-
-- local slash = require(Packages.slash)
64-
-- local stripBOM = require(Packages["strip-bom"])
65-
-- local jestEnvironmentModule = require(Packages.JestEnvironment)
66-
-- type Jest = jestEnvironmentModule.Jest
67-
-- type JestEnvironment = jestEnvironmentModule.JestEnvironment
68-
-- type Module = jestEnvironmentModule.Module
69-
-- type ModuleWrapper = jestEnvironmentModule.ModuleWrapper
70-
-- local jestFakeTimersModule = require(Packages.JestFakeTimers)
71-
-- type LegacyFakeTimers = jestFakeTimersModule.LegacyFakeTimers
72-
-- type ModernFakeTimers = jestFakeTimersModule.ModernFakeTimers
73-
-- local jestGlobalsModule = require(Packages.Dev.JestGlobals)
74-
-- local JestGlobals = jestGlobalsModule
75-
-- local jestSourceMapModule = require(Packages["@jest"]["source-map"])
76-
-- type SourceMapRegistry = jestSourceMapModule.SourceMapRegistry
77-
-- local jestTestResultModule = require(Packages.JestTestResult)
78-
-- type RuntimeTransformResult = jestTestResultModule.RuntimeTransformResult
79-
-- type V8CoverageResult = jestTestResultModule.V8CoverageResult
80-
-- local jestTransformModule = require(Packages["@jest"].transform)
81-
-- local CallerTransformOptions = jestTransformModule.CallerTransformOptions
82-
-- local ScriptTransformer = jestTransformModule.ScriptTransformer
83-
-- local ShouldInstrumentOptions = jestTransformModule.ShouldInstrumentOptions
84-
-- local TransformResult = jestTransformModule.TransformResult
85-
-- local TransformationOptions = jestTransformModule.TransformationOptions
86-
-- local handlePotentialSyntaxError = jestTransformModule.handlePotentialSyntaxError
87-
-- local shouldInstrument = jestTransformModule.shouldInstrument
8819
local jestTypesModule = require(Packages.JestTypes)
89-
-- type Config = jestTypesModule.Config
90-
-- type Config_Path = jestTypesModule.Config_Path
9120
type Config_ProjectConfig = jestTypesModule.Config_ProjectConfig
92-
-- type Global = jestTypesModule.Global
93-
-- type Global_TestFrameworkGlobals = jestTypesModule.Global_TestFrameworkGlobals
94-
-- local jestHasteMapModule = require(Packages["jest-haste-map"])
95-
-- type IModuleMap = jestHasteMapModule.IModuleMap
96-
-- local HasteMap = require(Packages["jest-haste-map"]).default
97-
-- local jestMessageUtilModule = require(Packages.JestMessageUtil)
98-
-- local formatStackTrace = jestMessageUtilModule.formatStackTrace
99-
-- local separateMessageFromStack = jestMessageUtilModule.separateMessageFromStack
100-
-- ROBLOX deviation END
10121
local jestMockModule = require(Packages.JestMock)
10222
-- ROBLOX deviation: not implemented yet
10323
-- type MockFunctionMetadata = jestMockModule.MockFunctionMetadata
@@ -110,20 +30,6 @@ local ModuleMocker = jestMockModule.ModuleMocker
11030
local jestMockGenvModule = require(Packages.JestMockGenv)
11131
local GlobalMocker = jestMockGenvModule.GlobalMocker
11232
type GlobalMocker = jestMockGenvModule.GlobalMocker
113-
-- ROBLOX deviation START: skipped
114-
-- local escapePathForRegex = require(Packages["jest-regex-util"]).escapePathForRegex
115-
-- local jestResolveModule = require(Packages["jest-resolve"])
116-
-- local Resolver = jestResolveModule.default
117-
-- local ResolveModuleConfig = jestResolveModule.ResolveModuleConfig
118-
-- local Snapshot = require(Packages.JestSnapshot)
119-
-- local jestUtilModule = require(Packages.JestUtil)
120-
-- local createDirectory = jestUtilModule.createDirectory
121-
-- local deepCyclicCopy = jestUtilModule.deepCyclicCopy
122-
-- local helpersModule = require(script.helpers)
123-
-- local createOutsideJestVmPath = helpersModule.createOutsideJestVmPath
124-
-- local decodePossibleOutsideJestVmPath = helpersModule.decodePossibleOutsideJestVmPath
125-
-- local findSiblingsWithFileExtension = helpersModule.findSiblingsWithFileExtension
126-
-- ROBLOX deviation END
12733
local typesModule = require(script.types)
12834
export type Context = typesModule.Context
12935
-- ROBLOX deviation START: skipped
@@ -151,6 +57,9 @@ type FakeTimers = JestFakeTimers.FakeTimers
15157
-- type JestGlobals = Global_TestFrameworkGlobals & {
15258
-- expect: typeof(__unhandledIdentifier__ --[[ ROBLOX TODO: Unhandled node for type: TSQualifiedName ]] --[[ JestGlobals.expect ]]),
15359
-- }
60+
61+
local LOADMODULE_ENABLED = pcall((debug :: any).loadmodule, Instance.new("ModuleScript"))
62+
15463
type JestGlobals = {
15564
expect: any,
15665
expectExtended: any,
@@ -1955,7 +1864,6 @@ function Runtime_private:_execModule(
19551864
local moduleFunction, defaultEnvironment, errorMessage, cleanupFn
19561865

19571866
local modulePath = localModule.filename
1958-
local loadModuleEnabled = pcall((debug :: any).loadmodule, Instance.new("ModuleScript"))
19591867

19601868
if self._loadedModuleFns and self._loadedModuleFns:has(modulePath) then
19611869
local loadedModule = self._loadedModuleFns:get(modulePath) :: { any }
@@ -1964,7 +1872,7 @@ function Runtime_private:_execModule(
19641872
else
19651873
-- Narrowing this type here lets us appease the type checker while still
19661874
-- counting on types for the rest of this file
1967-
if loadModuleEnabled then
1875+
if LOADMODULE_ENABLED then
19681876
local loadmodule: (ModuleScript) -> (any, string, () -> any) = debug["loadmodule"]
19691877
moduleFunction, errorMessage, cleanupFn = loadmodule(modulePath)
19701878
else
@@ -1998,7 +1906,7 @@ function Runtime_private:_execModule(
19981906
local isInternal = if options ~= nil and options.isInternalModule then options.isInternalModule else false
19991907

20001908
-- Data model references inside of sandbox
2001-
local dmScript = if loadModuleEnabled then defaultEnvironment.script else modulePath
1909+
local dmScript = if LOADMODULE_ENABLED then defaultEnvironment.script else modulePath
20021910
local dmGame = defaultEnvironment.game
20031911
local dmWorkspace = defaultEnvironment.workspace
20041912
local dmPlugin = defaultEnvironment.plugin

0 commit comments

Comments
 (0)