Skip to content
File

Blob: src/workerd/api/node/tests/vm-test.js

javascript318 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import * as vm from 'node:vm';
5import { doesNotThrow, notStrictEqual, strictEqual, throws } from 'node:assert';
6 
7export const vmTest = {
8 test() {
9 // Note: test was generated by claude with manual tweaks
10 
11 // Test constants
12 strictEqual(typeof vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER, 'symbol');
13 strictEqual(typeof vm.constants.DONT_CONTEXTIFY, 'symbol');
14 
15 // Test isContext function
16 // Should validate object argument
17 throws(() => vm.isContext(null), {
18 code: 'ERR_INVALID_ARG_TYPE',
19 });
20 throws(() => vm.isContext(undefined), {
21 code: 'ERR_INVALID_ARG_TYPE',
22 });
23 throws(() => vm.isContext('string'), {
24 code: 'ERR_INVALID_ARG_TYPE',
25 });
26 throws(() => vm.isContext(123), {
27 code: 'ERR_INVALID_ARG_TYPE',
28 });
29 
30 // Should work with objects and arrays (but always return false)
31 strictEqual(vm.isContext({}), false);
32 strictEqual(vm.isContext([]), false);
33 strictEqual(vm.isContext(new Object()), false);
34 
35 // Should return true for a valid vm.Context
36 const context = vm.createContext();
37 strictEqual(vm.isContext(context), true);
38 
39 // Basic construction should return a Script object that throws on run methods
40 const script1 = new vm.Script('code');
41 strictEqual(script1 instanceof vm.Script, true);
42 throws(() => script1.runInContext(context), {
43 code: 'ERR_METHOD_NOT_IMPLEMENTED',
44 });
45 throws(() => script1.runInNewContext(context), {
46 code: 'ERR_METHOD_NOT_IMPLEMENTED',
47 });
48 throws(() => script1.runInThisContext(), {
49 code: 'ERR_METHOD_NOT_IMPLEMENTED',
50 });
51 
52 // Test Script constructor argument validation
53 throws(() => new vm.Script('code', { filename: 123 }), {
54 code: 'ERR_INVALID_ARG_TYPE',
55 });
56 throws(() => new vm.Script('code', { lineOffset: 'invalid' }), {
57 code: 'ERR_INVALID_ARG_TYPE',
58 });
59 throws(() => new vm.Script('code', { columnOffset: 'invalid' }), {
60 code: 'ERR_INVALID_ARG_TYPE',
61 });
62 throws(() => new vm.Script('code', { cachedData: 'invalid' }), {
63 code: 'ERR_INVALID_ARG_TYPE',
64 });
65 throws(() => new vm.Script('code', { produceCachedData: 'invalid' }), {
66 code: 'ERR_INVALID_ARG_TYPE',
67 });
68 throws(
69 () => new vm.Script('code', { importModuleDynamically: 'invalid' }),
70 {
71 code: 'ERR_INVALID_ARG_TYPE',
72 }
73 );
74 
75 // Script can accept string options (should be treated as filename)
76 doesNotThrow(() => new vm.Script('code', 'filename.js'));
77 
78 // Test runInContext function
79 throws(() => vm.runInContext('this.a = 1;', {}), {
80 message: /must be an vm.Context/,
81 });
82 throws(() => vm.runInContext('code', null), {
83 code: 'ERR_INVALID_ARG_TYPE',
84 });
85 throws(() => vm.runInContext('code', 'invalid'), {
86 code: 'ERR_INVALID_ARG_TYPE',
87 });
88 
89 throws(() => vm.runInNewContext('code'), {
90 code: 'ERR_METHOD_NOT_IMPLEMENTED',
91 });
92 throws(() => vm.runInNewContext('code', {}), {
93 code: 'ERR_METHOD_NOT_IMPLEMENTED',
94 });
95 
96 // Test runInThisContext function
97 throws(() => vm.runInThisContext('code'), {
98 code: 'ERR_METHOD_NOT_IMPLEMENTED',
99 });
100 
101 // Test runInThisContext with string options
102 throws(() => vm.runInThisContext('code', 'filename.js'), {
103 code: 'ERR_METHOD_NOT_IMPLEMENTED',
104 });
105 
106 // Test createContext function with no options
107 const context1 = vm.createContext();
108 strictEqual(vm.isContext(context1), true);
109 
110 // Test createContext function passing in a context object
111 const context2 = vm.createContext(context1);
112 strictEqual(context2, context1);
113 
114 // Test createContext function passing in a non-context object
115 const obj = { a: 1 };
116 const context3 = vm.createContext(obj);
117 strictEqual(vm.isContext(context3), true);
118 notStrictEqual(context3, obj);
119 
120 // Test createContext argument validation
121 throws(() => vm.createContext({}, { name: 123 }), {
122 code: 'ERR_INVALID_ARG_TYPE',
123 });
124 throws(() => vm.createContext({}, { origin: 123 }), {
125 code: 'ERR_INVALID_ARG_TYPE',
126 });
127 throws(() => vm.createContext({}, { codeGeneration: 'invalid' }), {
128 code: 'ERR_INVALID_ARG_TYPE',
129 });
130 throws(() => vm.createContext({}, { importModuleDynamically: 'invalid' }), {
131 code: 'ERR_INVALID_ARG_TYPE',
132 });
133 throws(() => vm.createContext({}, { microtaskMode: 'invalid' }), {
134 code: 'ERR_INVALID_ARG_VALUE',
135 });
136 
137 // Test createScript function returns a Script that throws on run methods
138 const script2 = vm.createScript('code');
139 strictEqual(script2 instanceof vm.Script, true);
140 throws(() => script2.runInContext(context), {
141 code: 'ERR_METHOD_NOT_IMPLEMENTED',
142 });
143 throws(() => script2.runInNewContext(context), {
144 code: 'ERR_METHOD_NOT_IMPLEMENTED',
145 });
146 throws(() => script2.runInThisContext(), {
147 code: 'ERR_METHOD_NOT_IMPLEMENTED',
148 });
149 
150 // Test compileFunction
151 throws(() => vm.compileFunction('code'), {
152 code: 'ERR_METHOD_NOT_IMPLEMENTED',
153 });
154 
155 // Test compileFunction argument validation
156 throws(() => vm.compileFunction(123), {
157 code: 'ERR_INVALID_ARG_TYPE',
158 });
159 throws(() => vm.compileFunction('code', 'invalid_params'), {
160 code: 'ERR_INVALID_ARG_TYPE',
161 });
162 throws(() => vm.compileFunction('code', ['param'], { filename: 123 }), {
163 code: 'ERR_INVALID_ARG_TYPE',
164 });
165 throws(
166 () => vm.compileFunction('code', ['param'], { columnOffset: 'invalid' }),
167 {
168 code: 'ERR_INVALID_ARG_TYPE',
169 }
170 );
171 throws(
172 () => vm.compileFunction('code', ['param'], { lineOffset: 'invalid' }),
173 {
174 code: 'ERR_INVALID_ARG_TYPE',
175 }
176 );
177 throws(
178 () => vm.compileFunction('code', ['param'], { cachedData: 'invalid' }),
179 {
180 code: 'ERR_INVALID_ARG_TYPE',
181 }
182 );
183 throws(
184 () =>
185 vm.compileFunction('code', ['param'], { produceCachedData: 'invalid' }),
186 {
187 code: 'ERR_INVALID_ARG_TYPE',
188 }
189 );
190 throws(
191 () =>
192 vm.compileFunction('code', ['param'], {
193 importModuleDynamically: 'invalid',
194 }),
195 {
196 code: 'ERR_INVALID_ARG_TYPE',
197 }
198 );
199 throws(
200 () =>
201 vm.compileFunction('code', ['param'], { parsingContext: 'invalid' }),
202 {
203 code: 'ERR_INVALID_ARG_TYPE',
204 }
205 );
206 throws(
207 () =>
208 vm.compileFunction('code', ['param'], { contextExtensions: 'invalid' }),
209 {
210 code: 'ERR_INVALID_ARG_TYPE',
211 }
212 );
213 
214 // Test measureMemory
215 throws(() => vm.measureMemory(), {
216 code: 'ERR_METHOD_NOT_IMPLEMENTED',
217 });
218 throws(() => vm.measureMemory({}), {
219 code: 'ERR_METHOD_NOT_IMPLEMENTED',
220 });
221 
222 // Test measureMemory argument validation
223 throws(() => vm.measureMemory({ mode: 'invalid' }), {
224 code: 'ERR_INVALID_ARG_VALUE',
225 });
226 throws(() => vm.measureMemory({ execution: 'invalid' }), {
227 code: 'ERR_INVALID_ARG_VALUE',
228 });
229 
230 // Test edge cases with various input types
231 throws(() => vm.runInContext(null, {}), {
232 code: 'ERR_INVALID_ARG_TYPE',
233 });
234 throws(() => vm.runInNewContext(null), {
235 code: 'ERR_METHOD_NOT_IMPLEMENTED',
236 });
237 throws(() => vm.runInThisContext(null), {
238 code: 'ERR_METHOD_NOT_IMPLEMENTED',
239 });
240 
241 // Test with complex nested validation
242 throws(
243 () =>
244 vm.createContext(
245 {},
246 {
247 codeGeneration: {
248 strings: 'invalid',
249 },
250 }
251 ),
252 {
253 code: 'ERR_INVALID_ARG_TYPE',
254 }
255 );
256 
257 throws(
258 () =>
259 vm.createContext(
260 {},
261 {
262 codeGeneration: {
263 wasm: 'invalid',
264 },
265 }
266 ),
267 {
268 code: 'ERR_INVALID_ARG_TYPE',
269 }
270 );
271 
272 // Test compileFunction with invalid params array elements
273 throws(() => vm.compileFunction('code', [123]), {
274 code: 'ERR_INVALID_ARG_TYPE',
275 });
276 throws(() => vm.compileFunction('code', ['valid', null]), {
277 code: 'ERR_INVALID_ARG_TYPE',
278 });
279 
280 // Test compileFunction with invalid contextExtensions
281 throws(
282 () =>
283 vm.compileFunction('code', [], {
284 contextExtensions: ['invalid'],
285 }),
286 {
287 code: 'ERR_INVALID_ARG_TYPE',
288 }
289 );
290 
291 // Test timeout validation in runInThisContext options (must be strictly positive)
292 throws(() => vm.runInThisContext('code', { timeout: -1 }), {
293 code: 'ERR_OUT_OF_RANGE',
294 });
295 
296 // Test boolean validations
297 throws(() => vm.runInThisContext('code', { breakOnSigint: 'invalid' }), {
298 code: 'ERR_INVALID_ARG_TYPE',
299 });
300 throws(() => vm.runInThisContext('code', { displayErrors: 'invalid' }), {
301 code: 'ERR_INVALID_ARG_TYPE',
302 });
303 
304 // Test that constants object is frozen
305 throws(() => {
306 vm.constants.NEW_PROP = 'test';
307 });
308 throws(() => {
309 delete vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER;
310 });
311 
312 strictEqual(vm.default.Script, vm.Script);
313 strictEqual(vm.default.createContext, vm.createContext);
314 strictEqual(vm.default.isContext, vm.isContext);
315 strictEqual(vm.default.constants, vm.constants);
316 },
317};