summaryrefslogtreecommitdiff
path: root/test/parallel/test-vm-module-errors.js
diff options
context:
space:
mode:
Diffstat (limited to 'test/parallel/test-vm-module-errors.js')
-rw-r--r--test/parallel/test-vm-module-errors.js264
1 files changed, 264 insertions, 0 deletions
diff --git a/test/parallel/test-vm-module-errors.js b/test/parallel/test-vm-module-errors.js
new file mode 100644
index 0000000000..8bcb101ccc
--- /dev/null
+++ b/test/parallel/test-vm-module-errors.js
@@ -0,0 +1,264 @@
+'use strict';
+
+// Flags: --experimental-vm-modules
+
+const common = require('../common');
+common.crashOnUnhandledRejection();
+
+const assert = require('assert');
+
+const { Module, createContext } = require('vm');
+
+async function expectsRejection(fn, settings) {
+ const validateError = common.expectsError(settings);
+ // Retain async context.
+ const storedError = new Error('Thrown from:');
+ try {
+ await fn();
+ } catch (err) {
+ try {
+ validateError(err);
+ } catch (validationError) {
+ console.error(validationError);
+ console.error('Original error:');
+ console.error(err);
+ throw storedError;
+ }
+ return;
+ }
+ assert.fail('Missing expected exception');
+}
+
+async function createEmptyLinkedModule() {
+ const m = new Module('');
+ await m.link(common.mustNotCall());
+ return m;
+}
+
+async function checkArgType() {
+ common.expectsError(() => {
+ new Module();
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ type: TypeError
+ });
+
+ for (const invalidOptions of [
+ 0, 1, null, true, 'str', () => {}, Symbol.iterator
+ ]) {
+ common.expectsError(() => {
+ new Module('', invalidOptions);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ type: TypeError
+ });
+ }
+
+ for (const invalidLinker of [
+ 0, 1, undefined, null, true, 'str', {}, Symbol.iterator
+ ]) {
+ await expectsRejection(async () => {
+ const m = new Module('');
+ await m.link(invalidLinker);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ type: TypeError
+ });
+ }
+}
+
+// Check methods/properties can only be used under a specific state.
+async function checkModuleState() {
+ await expectsRejection(async () => {
+ const m = new Module('');
+ await m.link(common.mustNotCall());
+ assert.strictEqual(m.linkingStatus, 'linked');
+ await m.link(common.mustNotCall());
+ }, {
+ code: 'ERR_VM_MODULE_ALREADY_LINKED'
+ });
+
+ await expectsRejection(async () => {
+ const m = new Module('');
+ m.link(common.mustNotCall());
+ assert.strictEqual(m.linkingStatus, 'linking');
+ await m.link(common.mustNotCall());
+ }, {
+ code: 'ERR_VM_MODULE_ALREADY_LINKED'
+ });
+
+ common.expectsError(() => {
+ const m = new Module('');
+ m.instantiate();
+ }, {
+ code: 'ERR_VM_MODULE_NOT_LINKED'
+ });
+
+ await expectsRejection(async () => {
+ const m = new Module('import "foo";');
+ try {
+ await m.link(common.mustCall(() => ({})));
+ } catch (err) {
+ assert.strictEqual(m.linkingStatus, 'errored');
+ m.instantiate();
+ }
+ assert.fail('Unreachable');
+ }, {
+ code: 'ERR_VM_MODULE_NOT_LINKED'
+ });
+
+ {
+ const m = new Module('import "foo";');
+ await m.link(common.mustCall(async (module, specifier) => {
+ assert.strictEqual(module, m);
+ assert.strictEqual(specifier, 'foo');
+ assert.strictEqual(m.linkingStatus, 'linking');
+ common.expectsError(() => {
+ m.instantiate();
+ }, {
+ code: 'ERR_VM_MODULE_NOT_LINKED'
+ });
+ return new Module('');
+ }));
+ m.instantiate();
+ await m.evaluate();
+ }
+
+ await expectsRejection(async () => {
+ const m = new Module('');
+ await m.evaluate();
+ }, {
+ code: 'ERR_VM_MODULE_STATUS',
+ message: 'Module status must be one of instantiated, evaluated, and errored'
+ });
+
+ await expectsRejection(async () => {
+ const m = await createEmptyLinkedModule();
+ await m.evaluate();
+ }, {
+ code: 'ERR_VM_MODULE_STATUS',
+ message: 'Module status must be one of instantiated, evaluated, and errored'
+ });
+
+ common.expectsError(() => {
+ const m = new Module('');
+ m.error;
+ }, {
+ code: 'ERR_VM_MODULE_STATUS',
+ message: 'Module status must be errored'
+ });
+
+ await expectsRejection(async () => {
+ const m = await createEmptyLinkedModule();
+ m.instantiate();
+ await m.evaluate();
+ m.error;
+ }, {
+ code: 'ERR_VM_MODULE_STATUS',
+ message: 'Module status must be errored'
+ });
+
+ common.expectsError(() => {
+ const m = new Module('');
+ m.namespace;
+ }, {
+ code: 'ERR_VM_MODULE_STATUS',
+ message: 'Module status must not be uninstantiated or instantiating'
+ });
+
+ await expectsRejection(async () => {
+ const m = await createEmptyLinkedModule();
+ m.namespace;
+ }, {
+ code: 'ERR_VM_MODULE_STATUS',
+ message: 'Module status must not be uninstantiated or instantiating'
+ });
+}
+
+// Check link() fails when the returned module is not valid.
+async function checkLinking() {
+ await expectsRejection(async () => {
+ const m = new Module('import "foo";');
+ try {
+ await m.link(common.mustCall(() => ({})));
+ } catch (err) {
+ assert.strictEqual(m.linkingStatus, 'errored');
+ throw err;
+ }
+ assert.fail('Unreachable');
+ }, {
+ code: 'ERR_VM_MODULE_NOT_MODULE'
+ });
+
+ await expectsRejection(async () => {
+ const c = createContext({ a: 1 });
+ const foo = new Module('', { context: c });
+ await foo.link(common.mustNotCall());
+ const bar = new Module('import "foo";');
+ try {
+ await bar.link(common.mustCall(() => foo));
+ } catch (err) {
+ assert.strictEqual(bar.linkingStatus, 'errored');
+ throw err;
+ }
+ assert.fail('Unreachable');
+ }, {
+ code: 'ERR_VM_MODULE_DIFFERENT_CONTEXT'
+ });
+
+ await expectsRejection(async () => {
+ const erroredModule = new Module('import "foo";');
+ try {
+ await erroredModule.link(common.mustCall(() => ({})));
+ } catch (err) {
+ // ignored
+ } finally {
+ assert.strictEqual(erroredModule.linkingStatus, 'errored');
+ }
+
+ const rootModule = new Module('import "errored";');
+ await rootModule.link(common.mustCall(() => erroredModule));
+ }, {
+ code: 'ERR_VM_MODULE_LINKING_ERRORED'
+ });
+}
+
+// Check the JavaScript engine deals with exceptions correctly
+async function checkExecution() {
+ await (async () => {
+ const m = new Module('import { nonexistent } from "module";');
+ await m.link(common.mustCall(() => new Module('')));
+
+ // There is no code for this exception since it is thrown by the JavaScript
+ // engine.
+ assert.throws(() => {
+ m.instantiate();
+ }, SyntaxError);
+ })();
+
+ await (async () => {
+ const m = new Module('throw new Error();');
+ await m.link(common.mustNotCall());
+ m.instantiate();
+ const evaluatePromise = m.evaluate();
+ await evaluatePromise.catch(() => {});
+ assert.strictEqual(m.status, 'errored');
+ try {
+ await evaluatePromise;
+ } catch (err) {
+ assert.strictEqual(m.error, err);
+ return;
+ }
+ assert.fail('Missing expected exception');
+ })();
+}
+
+const finished = common.mustCall();
+
+(async function main() {
+ await checkArgType();
+ await checkModuleState();
+ await checkLinking();
+ await checkExecution();
+ finished();
+})();