| '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()); |