cosmjs-util/packages/cli/src/helpers.spec.ts
2020-04-17 08:40:04 +02:00

148 lines
6.6 KiB
TypeScript

import { createContext } from "vm";
import { executeJavaScript, executeJavaScriptAsync } from "./helpers";
describe("Helpers", () => {
describe("executeJavaScript", () => {
it("can execute simple JavaScript", () => {
{
const context = createContext({});
expect(executeJavaScript("123", "myfile.js", context)).toEqual(123);
}
{
const context = createContext({});
expect(executeJavaScript("1+1", "myfile.js", context)).toEqual(2);
}
});
it("can execute multiple commands in one context", () => {
const context = createContext({});
expect(executeJavaScript("let a", "myfile.js", context)).toBeUndefined();
expect(executeJavaScript("a = 2", "myfile.js", context)).toEqual(2);
expect(executeJavaScript("a", "myfile.js", context)).toEqual(2);
expect(executeJavaScript("let b = 3", "myfile.js", context)).toBeUndefined();
expect(executeJavaScript("a+b", "myfile.js", context)).toEqual(5);
});
it("has no require() in sandbox context", () => {
const context = createContext({});
expect(executeJavaScript("typeof require", "myfile.js", context)).toEqual("undefined");
});
it("has no exports object in sandbox context", () => {
const context = createContext({});
expect(executeJavaScript("typeof exports", "myfile.js", context)).toEqual("undefined");
});
it("has no module object in sandbox context", () => {
const context = createContext({});
expect(executeJavaScript("typeof module", "myfile.js", context)).toEqual("undefined");
});
it("can use require when passed into sandbox context", () => {
const context = createContext({ require: require });
expect(executeJavaScript("const path = require('path')", "myfile.js", context)).toBeUndefined();
expect(executeJavaScript("path.join('.')", "myfile.js", context)).toEqual(".");
});
it("can use module when passed into sandbox context", () => {
const context = createContext({ module: module });
expect(executeJavaScript("module.exports.fooTest", "myfile.js", context)).toBeUndefined();
expect(executeJavaScript("module.exports.fooTest = 'bar'", "myfile.js", context)).toEqual("bar");
expect(executeJavaScript("module.exports.fooTest", "myfile.js", context)).toEqual("bar");
// roll back change to module.exports
module.exports.fooTest = undefined;
});
it("can use exports when passed into sandbox context", () => {
const context = createContext({ exports: {} });
expect(executeJavaScript("exports.fooTest", "myfile.js", context)).toBeUndefined();
expect(executeJavaScript("exports.fooTest = 'bar'", "myfile.js", context)).toEqual("bar");
expect(executeJavaScript("exports.fooTest", "myfile.js", context)).toEqual("bar");
});
});
describe("executeJavaScriptAsync", () => {
it("can execute top level await with brackets", async () => {
const context = createContext({});
expect(await executeJavaScriptAsync("await (1)", "myfile.js", context)).toEqual(1);
});
it("can execute top level await without brackets", async () => {
const context = createContext({});
expect(await executeJavaScriptAsync("await 1", "myfile.js", context)).toEqual(1);
});
it("can handle multiple awaits", async () => {
const context = createContext({});
expect(await executeJavaScriptAsync("await 1 + await 2", "myfile.js", context)).toEqual(3);
});
it("errors for local declaration without assignment", async () => {
// `var a` cannot be converted into an assignment because it must not override an
// existing value. Thus we cannot execute it
const context = createContext({});
await executeJavaScriptAsync("var a", "myfile.js", context)
.then(() => fail("must not resolve"))
.catch((e) => expect(e).toMatch(/SyntaxError:/));
await executeJavaScriptAsync("let b", "myfile.js", context)
.then(() => fail("must not resolve"))
.catch((e) => expect(e).toMatch(/SyntaxError:/));
await executeJavaScriptAsync("const c", "myfile.js", context)
.then(() => fail("must not resolve"))
.catch((e) => expect(e).toMatch(/SyntaxError:/));
});
it("can execute multiple commands in one context", async () => {
const context = createContext({});
expect(await executeJavaScriptAsync("let a = 2", "myfile.js", context)).toBeUndefined();
expect(await executeJavaScriptAsync("a", "myfile.js", context)).toEqual(2);
expect(await executeJavaScriptAsync("a += 1", "myfile.js", context)).toEqual(3);
expect(await executeJavaScriptAsync("a += 7", "myfile.js", context)).toEqual(10);
expect(await executeJavaScriptAsync("a", "myfile.js", context)).toEqual(10);
expect((context as any).a).toEqual(10);
});
it("local variables are available across multiple calls in one context", async () => {
const context = createContext({});
expect(await executeJavaScriptAsync("let a = 3", "myfile.js", context)).toBeUndefined();
expect(await executeJavaScriptAsync("a", "myfile.js", context)).toEqual(3);
expect((context as any).a).toEqual(3);
});
it("works with strict mode", async () => {
const context = createContext({});
expect(await executeJavaScriptAsync('"use strict"; let a = 3', "myfile.js", context)).toBeUndefined();
expect(await executeJavaScriptAsync('"use strict"; a', "myfile.js", context)).toEqual(3);
expect((context as any).a).toEqual(3);
});
it("can reassign const", async () => {
// a side-effect of local variable assignment manipulation
const context = createContext({});
expect(await executeJavaScriptAsync("const a = 3", "myfile.js", context)).toBeUndefined();
expect((context as any).a).toEqual(3);
expect(await executeJavaScriptAsync("const a = 4", "myfile.js", context)).toBeUndefined();
expect((context as any).a).toEqual(4);
});
it("can execute timeout promise code", async () => {
const context = createContext({ setTimeout: setTimeout });
const code = "await (new Promise(resolve => setTimeout(() => resolve('job done'), 5)))";
expect(await executeJavaScriptAsync(code, "myfile.js", context)).toEqual("job done");
});
it("can execute timeout code in multiple statements", async () => {
const context = createContext({ setTimeout: setTimeout });
const code = `
const promise = new Promise(resolve => {
setTimeout(() => resolve('job done'), 5);
});
await (promise);
`;
expect(await executeJavaScriptAsync(code, "myfile.js", context)).toEqual("job done");
});
});
});