'use strict'; // Check vm.constants.DONT_CONTEXTIFY works. const common = require('../common'); const assert = require('assert'); const vm = require('vm'); const fixtures = require('../common/fixtures'); { // Check identity of the returned object. const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); // The globalThis in the new context should be reference equal to the returned object. assert.strictEqual(vm.runInContext('globalThis', context), context); assert(vm.isContext(context)); assert.strictEqual(typeof context.Array, 'function'); // Can access builtins directly. assert.deepStrictEqual(Object.keys(context), []); // Properties on the global proxy are not enumerable } { // Check that vm.createContext can return the original context if re-passed. const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); const context2 = new vm.createContext(context); assert.strictEqual(context, context2); } { // Check that the context is vanilla and that Script.runInContext works. const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); const result = new vm.Script('globalThis.hey = 1; Object.freeze(globalThis); globalThis.process') .runInContext(context); assert.strictEqual(globalThis.hey, undefined); // Should not leak into current context. assert.strictEqual(result, undefined); // Vanilla context has no Node.js globals } { // Check Script.runInNewContext works. const result = new vm.Script('globalThis.hey = 1; Object.freeze(globalThis); globalThis.process') .runInNewContext(vm.constants.DONT_CONTEXTIFY); assert.strictEqual(globalThis.hey, undefined); // Should not leak into current context. assert.strictEqual(result, undefined); // Vanilla context has no Node.js globals } { // Check that vm.runInNewContext() works const result = vm.runInNewContext( 'globalThis.hey = 1; Object.freeze(globalThis); globalThis.process', vm.constants.DONT_CONTEXTIFY); assert.strictEqual(globalThis.hey, undefined); // Should not leak into current context. assert.strictEqual(result, undefined); // Vanilla context has no Node.js globals } { // Check that the global object of vanilla contexts work as expected. const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); // Check mutation via globalThis. vm.runInContext('globalThis.foo = 1;', context); assert.strictEqual(globalThis.foo, undefined); // Should not pollute the current context. assert.strictEqual(context.foo, 1); assert.strictEqual(vm.runInContext('globalThis.foo', context), 1); assert.strictEqual(vm.runInContext('foo', context), 1); // Check mutation from outside. context.foo = 2; assert.strictEqual(context.foo, 2); assert.strictEqual(vm.runInContext('globalThis.foo', context), 2); assert.strictEqual(vm.runInContext('foo', context), 2); // Check contextual mutation. vm.runInContext('bar = 1;', context); assert.strictEqual(globalThis.bar, undefined); // Should not pollute the current context. assert.strictEqual(context.bar, 1); assert.strictEqual(vm.runInContext('globalThis.bar', context), 1); assert.strictEqual(vm.runInContext('bar', context), 1); // Check adding new property from outside. context.baz = 1; assert.strictEqual(context.baz, 1); assert.strictEqual(vm.runInContext('globalThis.baz', context), 1); assert.strictEqual(vm.runInContext('baz', context), 1); // Check mutation via Object.defineProperty(). vm.runInContext('Object.defineProperty(globalThis, "qux", {' + 'enumerable: false, configurable: false, get() { return 1; } })', context); assert.strictEqual(globalThis.qux, undefined); // Should not pollute the current context. assert.strictEqual(context.qux, 1); assert.strictEqual(vm.runInContext('qux', context), 1); const desc = Object.getOwnPropertyDescriptor(context, 'qux'); assert.strictEqual(desc.enumerable, false); assert.strictEqual(desc.configurable, false); assert.strictEqual(typeof desc.get, 'function'); assert.throws(() => { context.qux = 1; }, { name: 'TypeError' }); assert.throws(() => { Object.defineProperty(context, 'qux', { value: 1 }); }, { name: 'TypeError' }); // Setting a value without a setter fails silently. assert.strictEqual(vm.runInContext('qux = 2; qux', context), 1); assert.throws(() => { vm.runInContext('Object.defineProperty(globalThis, "qux", { value: 1 });'); }, { name: 'TypeError' }); } function checkFrozen(context) { // Check mutation via globalThis. vm.runInContext('globalThis.foo = 1', context); // Invoking setters on freezed object fails silently. assert.strictEqual(context.foo, undefined); assert.strictEqual(vm.runInContext('globalThis.foo', context), undefined); assert.throws(() => { vm.runInContext('foo', context); // It should not be looked up contextually. }, { name: 'ReferenceError' }); // Check mutation from outside. assert.throws(() => { context.foo = 2; }, { name: 'TypeError' }); assert.strictEqual(context.foo, undefined); assert.strictEqual(vm.runInContext('globalThis.foo', context), undefined); assert.throws(() => { vm.runInContext('foo', context); // It should not be looked up contextually. }, { name: 'ReferenceError' }); // Check contextual mutation. vm.runInContext('bar = 1', context); // Invoking setters on freezed object fails silently. assert.strictEqual(context.bar, undefined); assert.strictEqual(vm.runInContext('globalThis.bar', context), undefined); assert.throws(() => { vm.runInContext('bar', context); // It should not be looked up contextually. }, { name: 'ReferenceError' }); // Check mutation via Object.defineProperty(). assert.throws(() => { vm.runInContext('Object.defineProperty(globalThis, "qux", {' + 'enumerable: false, configurable: false, get() { return 1; } })', context); }, { name: 'TypeError' }); assert.strictEqual(context.qux, undefined); assert.strictEqual(vm.runInContext('globalThis.qux', context), undefined); assert.strictEqual(Object.getOwnPropertyDescriptor(context, 'qux'), undefined); assert.throws(() => { Object.defineProperty(context, 'qux', { value: 1 }); }, { name: 'TypeError' }); assert.throws(() => { vm.runInContext('qux', context); }, { name: 'ReferenceError' }); } { // Check freezing the vanilla context's global object from within the context. const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); // Only vanilla contexts' globals can be freezed. Contextified global objects cannot be freezed // due to the presence of interceptors. vm.runInContext('Object.freeze(globalThis)', context); checkFrozen(context); } { // Check freezing the vanilla context's global object from outside the context. const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); Object.freeze(context); checkFrozen(context); } // Check importModuleDynamically works. (async function() { { const moduleUrl = fixtures.fileURL('es-modules', 'message.mjs'); const namespace = await import(moduleUrl.href); // Check dynamic import works const context = vm.createContext(vm.constants.DONT_CONTEXTIFY); const script = new vm.Script(`import(${JSON.stringify(moduleUrl)})`, { importModuleDynamically: vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER, }); const promise = script.runInContext(context); assert.strictEqual(await promise, namespace); } })().catch(common.mustNotCall());