Comparing version 3.4.2 to 3.5.0
@@ -12,2 +12,3 @@ 'use strict'; | ||
this.args = options.hostArguments || []; | ||
this.transform = options.transform || (x => x); | ||
@@ -26,2 +27,4 @@ if (typeof this.args === 'string') { | ||
code = this.transform(code); | ||
if (options.async) { | ||
@@ -28,0 +31,0 @@ return code; |
@@ -7,4 +7,7 @@ 'use strict'; | ||
class BrowserAgent extends Agent { | ||
constructor (hostPath) { | ||
super(hostPath); | ||
constructor (options) { | ||
super(options); | ||
this.webHost = options.webHost || 'localhost'; | ||
this.webPort = options.webPort || 1337; | ||
this.id = agentId++; | ||
@@ -15,4 +18,4 @@ } | ||
return Server.start(this.id).then(_ => { | ||
this._url = 'http://localhost:1337/?clientId=' + this.id + | ||
'&shortName=' + this.shortName; | ||
this._url = `http://${this.webHost}:${this.webPort}/` + | ||
`?clientId=${this.id}&shortName=${this.shortName}`; | ||
return this; | ||
@@ -19,0 +22,0 @@ }); |
@@ -20,6 +20,18 @@ 'use strict'; | ||
// Because the input code may modify the global environment in ways that | ||
// interfere with the normal operation of `eshost`, it must be run in a | ||
// dedicated virtual machine. | ||
// | ||
// The "context" object for this virtual machine should be re-used if the | ||
// input code invokes `$.evalScript`, but Node.js does not tolerate sharing | ||
// context objects across virtual machines in this manner. Instead, define | ||
// a new method for evaluating scripts in the context created here. | ||
code = ` | ||
Function("return this;")().require = require; | ||
var vm = require("vm"); | ||
vm.runInThisContext(${JSON.stringify(code)}); | ||
var eshostContext = vm.createContext({ require, console }); | ||
vm.runInESHostContext = function(code, options) { | ||
return vm.runInContext(code, eshostContext, options); | ||
}; | ||
vm.runInESHostContext(${JSON.stringify(code)}); | ||
`; | ||
@@ -26,0 +38,0 @@ |
@@ -16,6 +16,4 @@ 'use strict'; | ||
createChildProcess(args) { | ||
args = args || []; | ||
args = args.concat(this.args); | ||
return cp.spawn(this.hostPath, args); | ||
createChildProcess(args = []) { | ||
return cp.spawn(this.hostPath, this.args.concat(args)); | ||
} | ||
@@ -22,0 +20,0 @@ |
@@ -56,3 +56,3 @@ 'use strict'; | ||
socket.on('print', str => this.gotStdout(str)); | ||
socket.on('print', ({value}) => this.gotStdout(value)); | ||
socket.on('execDone', _ => this.gotExecDone()); | ||
@@ -59,0 +59,0 @@ if (this._onGotSocket) this._onGotSocket(this); |
@@ -66,3 +66,3 @@ 'use strict'; | ||
return baseP.then(_ => super.destroy()).then(_ => this._driver.quit()); | ||
return baseP.then(_ => this._driver.quit()).then(_ => super.destroy()); | ||
} | ||
@@ -69,0 +69,0 @@ } |
{ | ||
"name": "eshost", | ||
"version": "3.4.2", | ||
"version": "3.5.0", | ||
"description": "Invoke ECMAScript scripts in any command line JS engine.", | ||
@@ -5,0 +5,0 @@ "main": "lib/eshost.js", |
@@ -58,2 +58,10 @@ ## eshost | ||
* **hostArguments**: Command line arguments used when invoking your host. Not supported for browser hosts. **hostArguments** is an array of strings as you might pass to Node's spawn API. | ||
* **transform**: A function to map the source to some other source before running the result on the underlying host. | ||
* **webHost**: for web browser hosts only; URL host name from which to serve browser assets; optional; defaults to `"localhost"` | ||
* **webPort**: for web browser hosts only; URL port number from which to serve browser assets; optional; defaults to `1337` | ||
* **capabilities**: for `remote` host only; the Selenium/WebDriver capabilities to request for the remote session; all specified attributes will be forwarded to the server; [a listing of available attributes is available in the Selenium project's wiki](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities); the following attributes are required: | ||
* **capabilities.browserName** | ||
* **capabilities.platform** | ||
* **capabilities.version** | ||
* **webdriverServer**: for `remote` host only; URL of the WebDriver server to which commands should be issued | ||
@@ -145,1 +153,29 @@ ### Agent API | ||
Sets a global property name to value. | ||
### Running the tests | ||
This project's tests can be executed with the following command: | ||
npm test | ||
The above command will cause tests to be run against all supported hosts. | ||
Executables for each host must be available on the system's `PATH` environment | ||
variable. | ||
One or more hosts may be skipped from the test run by setting corresponding | ||
environment variables whose name match the pattern `ESHOST_SKIP_*`, where `*` | ||
is the capitalized name of the host. For example, in a Unix-like system, the | ||
following command executes the project's tests but skips JavaScriptCore and D8 | ||
tests: | ||
ESHOST_SKIP_JSC=1 ESHOST_SKIP_D8=1 npm test | ||
Tests for the "remote" agent can be configured to run against any arbitrary | ||
Selenium/WebDriver configuration through the specification of the following | ||
environment variables: `ESHOST_REMOTE_BROWSERNAME`, `ESHOST_REMOTE_VERSION`, | ||
`ESHOST_REMOTE_PLATFORM`. These values are used to define the host's | ||
capabilities; see the above documentation of `eshost.createAgent` for more | ||
details. For example, in a Unix-like system, the following command executes the | ||
project's tests in a remote instance of the Firefox web browser: | ||
ESHOST_REMOTE_BROWSERNAME=firefox npm test |
@@ -23,2 +23,8 @@ (function() { | ||
var fscript = fdoc.createElement('script'); | ||
// The following is a workaround for a bug in Chromium related to reporting | ||
// errors produced from evaluating code using `eval`. | ||
// https://bugs.chromium.org/p/chromium/issues/detail?id=746564 | ||
fdoc.write('<body>'); | ||
fscript.textContent = this.source; | ||
@@ -86,4 +92,7 @@ fdoc.body.appendChild(fscript); | ||
function print(str) { | ||
$.socket.emit('print', str); | ||
function print(value) { | ||
// If the `undefined` value is emitted directly, Socket.io will transmit the | ||
// `null` value in its place, invalidating the reported output. Emit the | ||
// value as a property of an ordinary object to avoid this behavior. | ||
$.socket.emit('print', {value: value}); | ||
} | ||
@@ -90,0 +99,0 @@ |
@@ -33,3 +33,3 @@ var vm = require('vm'); | ||
} else { | ||
vm.runInThisContext(code, {displayErrors: false}); | ||
vm.runInESHostContext(code, {displayErrors: false}); | ||
} | ||
@@ -36,0 +36,0 @@ |
@@ -6,14 +6,24 @@ 'use strict'; | ||
const isWindows = process.platform === 'win32' || | ||
process.env.OSTYPE === 'cygwin' || | ||
process.env.OSTYPE === 'msys'; | ||
const remoteCapabilities = { | ||
browserName: process.env.ESHOST_REMOTE_BROWSERNAME || 'firefox', | ||
platform: process.env.ESHOST_REMOTE_PLATFORM || 'ANY', | ||
version: process.env.ESHOST_REMOTE_VERSION || '' | ||
}; | ||
const hosts = [ | ||
['./hosts/js.exe', 'jsshell'], | ||
['./hosts/ch.exe', 'ch'], | ||
['c:/program files/nodejs/node.exe', 'node'], | ||
['../v8/build/Release/d8.exe', 'd8'], | ||
['../webkit/build/bin64/jsc.exe', 'jsc'], | ||
/*[undefined, 'chrome'],*/ | ||
//['C:/Program Files (x86)/Mozilla Firefox/firefox.exe', 'firefox'], | ||
/*['C:/Program Files (x86)/Nightly/firefox.exe', 'firefox'], | ||
['C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', 'chrome'], | ||
*/ | ||
['jsshell', { hostPath: 'js' }], | ||
['ch', { hostPath: 'ch' }], | ||
['node', { hostPath: 'node' }], | ||
['d8', { hostPath: 'd8' }], | ||
['jsc', { hostPath: 'jsc' }], | ||
['chrome', { hostPath: 'chrome' }], | ||
['firefox', { hostPath: 'firefox' }], | ||
['remote', { | ||
webdriverServer: 'http://localhost:4444/wd/hub', | ||
capabilities: remoteCapabilities | ||
} | ||
], | ||
]; | ||
@@ -28,320 +38,497 @@ | ||
hosts.forEach(function (record) { | ||
const host = record[0]; | ||
const type = record[1]; | ||
const type = record[0]; | ||
const options = record[1]; | ||
const effectiveType = type === 'remote' ? | ||
options.capabilities.browserName : type; | ||
if (options.hostPath && isWindows) { | ||
options.hostPath += '.exe'; | ||
} | ||
describe(`${type} (${host})`, function () { | ||
describe(`${type} (${options.hostPath || effectiveType})`, function () { | ||
this.timeout(20000); | ||
let agent; | ||
before(function() { | ||
return runify.createAgent(type, { hostPath: host }).then(a => agent = a); | ||
}); | ||
if (process.env['ESHOST_SKIP_' + type.toUpperCase()]) { | ||
this.skip(); | ||
return; | ||
} | ||
after(function() { | ||
return agent.destroy(); | ||
if (type === 'remote') { | ||
this.timeout(60 * 1000); | ||
} | ||
}); | ||
it('allows custom shortNames', function() { | ||
return runify.createAgent(type, { hostPath: host, shortName: '$testing' }).then(agent => { | ||
return agent.evalScript('$testing.evalScript("print(1)")').then(result => { | ||
assert(result.error === null, 'no error'); | ||
assert.equal(result.stdout.indexOf('1'), 0); | ||
}); | ||
describe('normal script evaluation', function() { | ||
let agent; | ||
before(function() { | ||
return runify.createAgent(type, options) | ||
.then(a => agent = a); | ||
}); | ||
}); | ||
it('runs SyntaxErrors', function () { | ||
return agent.evalScript('foo x++').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.name, 'SyntaxError'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
after(function() { | ||
return agent.destroy(); | ||
}); | ||
}); | ||
it('runs thrown SyntaxErrors', function () { | ||
return agent.evalScript('throw new SyntaxError("Custom Message");').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
it('runs SyntaxErrors', function () { | ||
return agent.evalScript('foo x++').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.name, 'SyntaxError'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
}); | ||
}); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'SyntaxError'); | ||
assert.equal(result.error.stack[0].lineNumber, 1); | ||
it('runs thrown SyntaxErrors', function () { | ||
return agent.evalScript('throw new SyntaxError("Custom Message");').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'SyntaxError'); | ||
assert.equal(result.error.stack[0].lineNumber, 1); | ||
}); | ||
}); | ||
}); | ||
it('runs thrown TypeErrors', function () { | ||
return agent.evalScript('throw new TypeError("Custom Message");').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
it('runs thrown TypeErrors', function () { | ||
return agent.evalScript('throw new TypeError("Custom Message");').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'TypeError'); | ||
assert.equal(result.error.stack[0].lineNumber, 1); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'TypeError'); | ||
assert.equal(result.error.stack[0].lineNumber, 1); | ||
}); | ||
}); | ||
}); | ||
it('runs thrown RangeErrors', function () { | ||
return agent.evalScript('throw new RangeError("Custom Message");').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
it('runs thrown RangeErrors', function () { | ||
return agent.evalScript('throw new RangeError("Custom Message");').then(function (result) { | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'RangeError'); | ||
assert.equal(result.error.stack[0].lineNumber, 1); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'RangeError'); | ||
assert.equal(result.error.stack[0].lineNumber, 1); | ||
}); | ||
}); | ||
}); | ||
it('runs thrown Errors', function () { | ||
return agent.evalScript('throw new Error("Custom Message");').then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'Error'); | ||
it('runs thrown Errors', function () { | ||
return agent.evalScript('throw new Error("Custom Message");').then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'Error'); | ||
}); | ||
}); | ||
}); | ||
it('runs thrown custom Errors', function () { | ||
return agent.evalScript('function Foo1Error(msg) { this.name = "Foo1Error"; this.message = msg }; Foo1Error.prototype = Error.prototype; throw new Foo1Error("Custom Message");').then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'Foo1Error'); | ||
it('runs thrown custom Errors', function () { | ||
return agent.evalScript('function Foo1Error(msg) { this.name = "Foo1Error"; this.message = msg }; Foo1Error.prototype = Error.prototype; throw new Foo1Error("Custom Message");').then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, 'Custom Message'); | ||
assert.equal(result.error.name, 'Foo1Error'); | ||
}); | ||
}); | ||
}); | ||
it('runs thrown custom Errors that don\'t have Error.prototype', function () { | ||
return agent.evalScript(` | ||
function Foo2Error(msg) { | ||
this.message = msg; | ||
} | ||
Foo2Error.prototype.name = 'Foo2Error'; | ||
Foo2Error.prototype.toString = function () { | ||
return 'Foo2Error: ' + this.message; | ||
} | ||
it('runs thrown custom Errors that don\'t have Error.prototype', function () { | ||
return agent.evalScript(` | ||
function Foo2Error(msg) { | ||
this.message = msg; | ||
} | ||
Foo2Error.prototype.name = 'Foo2Error'; | ||
Foo2Error.prototype.toString = function () { | ||
return 'Foo2Error: ' + this.message; | ||
} | ||
throw new Foo2Error('FAIL!'); | ||
`).then(result => { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, 'FAIL!'); | ||
assert.equal(result.error.name, 'Foo2Error'); | ||
}); | ||
}) | ||
throw new Foo2Error('FAIL!'); | ||
`).then(result => { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, 'FAIL!'); | ||
assert.equal(result.error.name, 'Foo2Error'); | ||
}); | ||
}) | ||
it('runs thrown Errors without messages', function () { | ||
return agent.evalScript('throw new Error();').then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, undefined); | ||
assert.equal(result.error.name, 'Error'); | ||
it('runs thrown Errors without messages', function () { | ||
return agent.evalScript('throw new Error();').then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert.equal(result.error.message, undefined); | ||
assert.equal(result.error.name, 'Error'); | ||
}); | ||
}); | ||
}); | ||
it('runs thrown errors from eval', function () { | ||
return agent.evalScript('eval("\'\\u000Astr\\u000Aing\\u000A\'") === "\\u000Astr\\u000Aing\\u000A"') | ||
.then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert(result.error.message); // message should be present (but is implementation defined) | ||
assert.equal(result.error.name, 'SyntaxError'); | ||
it('runs thrown errors from eval', function () { | ||
return agent.evalScript('eval("\'\\u000Astr\\u000Aing\\u000A\'") === "\\u000Astr\\u000Aing\\u000A"') | ||
.then(function (result) { | ||
assert.equal(result.stdout, '', 'stdout not present'); | ||
assert(result.error, 'error is present'); | ||
assert(result.error.message); // message should be present (but is implementation defined) | ||
assert.equal(result.error.name, 'SyntaxError'); | ||
}); | ||
}); | ||
}); | ||
it('gathers stdout', function () { | ||
return agent.evalScript('print("foo")').then(function(result) { | ||
assert(result.stdout.match(/^foo\r?\n/), 'Unexpected stdout: ' + result.stdout); | ||
it('gathers stdout', function () { | ||
return agent.evalScript('print("foo")').then(function(result) { | ||
assert(result.stdout.match(/^foo\r?\n/), 'Unexpected stdout: ' + result.stdout); | ||
}); | ||
}); | ||
}); | ||
it('can eval in new realms', function () { | ||
return agent.evalScript(` | ||
var x = 2; | ||
$child = $.createRealm(); | ||
$child.evalScript("var x = 1; print(x);"); | ||
print(x); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('can eval in new realms', function () { | ||
return agent.evalScript(` | ||
var x = 2; | ||
$child = $.createRealm(); | ||
$child.evalScript("var x = 1; print(x);"); | ||
print(x); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('can create new realms', function() { | ||
return agent.evalScript(` | ||
var sub$ = $.createRealm({}); | ||
sub$.evalScript("var x = 1"); | ||
sub$.evalScript("print(x)"); | ||
subsub$ = sub$.createRealm({}); | ||
subsub$.evalScript("var x = 2"); | ||
subsub$.evalScript("print(2)"); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('can create new realms', function() { | ||
return agent.evalScript(` | ||
var sub$ = $.createRealm({}); | ||
sub$.evalScript("var x = 1"); | ||
sub$.evalScript("print(x)"); | ||
subsub$ = sub$.createRealm({}); | ||
subsub$.evalScript("var x = 2"); | ||
subsub$.evalScript("print(2)"); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('can set globals in new realms', function () { | ||
return agent.evalScript(` | ||
var x = 1; | ||
$child = $.createRealm({globals: {x: 2}}); | ||
$child.evalScript("print(x);"); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('can set globals in new realms', function () { | ||
return agent.evalScript(` | ||
var x = 1; | ||
$child = $.createRealm({globals: {x: 2}}); | ||
$child.evalScript("print(x);"); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('can eval in new scripts', function () { | ||
return agent.evalScript(` | ||
var x = 2; | ||
$.evalScript("x = 3;"); | ||
print(x); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^3\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('can eval in new scripts', function () { | ||
return agent.evalScript(` | ||
var x = 2; | ||
$.evalScript("x = 3;"); | ||
print(x); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^3\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('returns errors from evaling in new script', function () { | ||
return agent.evalScript(` | ||
var completion = $.evalScript("x+++"); | ||
print(completion.value.name); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^SyntaxError\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('returns errors from evaling in new script', function () { | ||
return agent.evalScript(` | ||
var completion = $.evalScript("x+++"); | ||
print(completion.value.name); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^SyntaxError\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('can eval lexical bindings in new scripts', function () { | ||
return agent.evalScript(` | ||
$.evalScript("'use strict'; let x = 3;"); | ||
print(x); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^3\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('can eval lexical bindings in new scripts', function () { | ||
return agent.evalScript(` | ||
$.evalScript("'use strict'; let x = 3;"); | ||
print(x); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^3\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('can set properties in new realms', function() { | ||
return agent.evalScript(` | ||
var sub$ = $.createRealm({}); | ||
sub$.evalScript("var x = 1"); | ||
sub$.evalScript("print(x)"); | ||
it('can set properties in new realms', function() { | ||
return agent.evalScript(` | ||
var sub$ = $.createRealm({}); | ||
sub$.evalScript("var x = 1"); | ||
sub$.evalScript("print(x)"); | ||
sub$.setGlobal("x", 2); | ||
sub$.setGlobal("x", 2); | ||
sub$.evalScript("print(x)"); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
sub$.evalScript("print(x)"); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n2\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('can access properties from new realms', function() { | ||
return agent.evalScript(` | ||
var sub$ = $.createRealm({}); | ||
sub$.evalScript("var x = 1"); | ||
it('can access properties from new realms', function() { | ||
return agent.evalScript(` | ||
var sub$ = $.createRealm({}); | ||
sub$.evalScript("var x = 1"); | ||
print(sub$.getGlobal("x")); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
print(sub$.getGlobal("x")); | ||
`).then(function(result) { | ||
assert(result.stdout.match(/^1\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('runs async code', function () { | ||
return agent.evalScript(` | ||
if ($.global.Promise === undefined) { | ||
print('async result'); | ||
$.destroy() | ||
} else { | ||
Promise.resolve().then(function () { | ||
it('runs async code', function () { | ||
return agent.evalScript(` | ||
if ($.global.Promise === undefined) { | ||
print('async result'); | ||
$.destroy() | ||
}); | ||
} | ||
`, { async: true }).then(result => { | ||
assert(result.stdout.match(/async result/), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
} else { | ||
Promise.resolve().then(function () { | ||
print('async result'); | ||
$.destroy() | ||
}); | ||
} | ||
`, { async: true }).then(result => { | ||
assert(result.stdout.match(/async result/), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('accepts destroy callbacks', function () { | ||
return agent.evalScript(` | ||
$child = $.createRealm({ destroy: function () { print("destroyed") }}); | ||
$child.destroy(); | ||
`) | ||
.then(result => { | ||
assert(result.stdout.match(/destroyed/), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('accepts destroy callbacks', function () { | ||
return agent.evalScript(` | ||
$child = $.createRealm({ destroy: function () { print("destroyed") }}); | ||
$child.destroy(); | ||
`) | ||
.then(result => { | ||
assert(result.stdout.match(/destroyed/), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
}); | ||
it('runs in the proper mode', function () { | ||
return agent.evalScript(` | ||
"use strict" | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
it('runs in the proper mode', function () { | ||
return agent.evalScript(` | ||
'use strict' | ||
"use strict" | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
`) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
return agent.evalScript(` | ||
'use strict' | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
return agent.evalScript(` | ||
function foo() { print(this === Function('return this;')()) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
return agent.evalScript(` | ||
/*--- | ||
---*/ | ||
"use strict"; | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
return agent.evalScript(` | ||
/*--- | ||
---*/ | ||
" some other prolog " | ||
"use strict"; | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
return agent.evalScript(` | ||
// normal comment | ||
/*--- | ||
---*/ | ||
" some other prolog " | ||
// another comment | ||
"use strict"; | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
}); | ||
}); | ||
it("prints values correctly", function () { | ||
return agent.evalScript(` | ||
function foo() { print(this === Function('return this;')()) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
print(undefined); | ||
print(null); | ||
print('string'); | ||
print(true); | ||
print(false); | ||
print(0); | ||
print(1); | ||
print(1.2); | ||
print(-1); | ||
`).then((result) => { | ||
var values; | ||
assert.equal(result.stderr, ''); | ||
values = result.stdout.split(/\r?\n/); | ||
assert.equal(values[0], 'undefined') | ||
assert.equal(values[1], 'null') | ||
assert.equal(values[2], 'string') | ||
assert.equal(values[3], 'true') | ||
assert.equal(values[4], 'false') | ||
assert.equal(values[5], '0') | ||
assert.equal(values[6], '1') | ||
assert.equal(values[7], '1.2') | ||
assert.equal(values[8], '-1') | ||
}); | ||
}); | ||
it('tolerates broken execution environments', function () { | ||
return agent.evalScript(` | ||
/*--- | ||
---*/ | ||
"use strict"; | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
Object.defineProperty(Object.prototype, "length", { | ||
get: function () { | ||
return 1; | ||
}, | ||
configurable: true | ||
}); | ||
print('okay'); | ||
`).then((result) => { | ||
assert.equal(result.stderr, ''); | ||
assert(result.stdout.match(/^okay\r?\n/m)); | ||
}); | ||
}); | ||
it('supports realm nesting', function () { | ||
return agent.evalScript(` | ||
/*--- | ||
---*/ | ||
" some other prolog " | ||
"use strict"; | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
x = 0; | ||
$.createRealm().evalScript(\` | ||
x = ''; | ||
$.createRealm().evalScript(\\\` | ||
x = {}; | ||
print(typeof x); | ||
\\\`); | ||
print(typeof x); | ||
\`); | ||
print(typeof x); | ||
`) | ||
.then((result) => { | ||
assert.equal(result.stderr, ''); | ||
assert(result.stdout.match(/^object\r?\nstring\r?\nnumber\r?\n/m)); | ||
}); | ||
}); | ||
it('observes correct cross-script interaction semantics', function () { | ||
return agent.evalScript(` | ||
// normal comment | ||
/*--- | ||
---*/ | ||
" some other prolog " | ||
// another comment | ||
"use strict"; | ||
function foo() { print(this === undefined) } | ||
foo(); | ||
`); | ||
}) | ||
.then(function(result) { | ||
assert(result.stdout.match(/^true\r?\n/m), 'Unexpected stdout: ' + result.stdout + result.stderr); | ||
print($.evalScript('let eshost;').type); | ||
print($.evalScript('let eshost;').type); | ||
`) | ||
.then((result) => { | ||
assert.equal(result.stderr, ''); | ||
assert(result.stdout.match(/^normal\r?\nthrow/m)); | ||
}); | ||
}); | ||
// mostly this test shouldn't hang (if it hangs, it's a bug) | ||
it('can kill infinite loops', function () { | ||
// The GeckoDriver project cannot currently destroy browsing sessions | ||
// whose main thread is blocked. | ||
// https://github.com/mozilla/geckodriver/issues/825 | ||
if (effectiveType === 'firefox') { | ||
this.skip(); | ||
return; | ||
} | ||
var resultP = agent.evalScript(`while (true) { }; print(2);`); | ||
return timeout(100).then(_ => { | ||
var stopP = agent.stop(); | ||
return Promise.all([resultP, stopP]); | ||
}).then(record => { | ||
const result = record[0]; | ||
assert(!result.stdout.match(/2/), 'Unexpected stdout: ' + result.stdout); | ||
}); | ||
}); | ||
it('creates "optional" environments correctly (hostArgs)', function() { | ||
// browsers are irrelevant to this test | ||
if (['firefox', 'chrome', 'remote'].includes(type)) { | ||
this.skip(); | ||
return; | ||
} | ||
let source = ''; | ||
let hostArguments = ''; | ||
// Setup special cases | ||
if (type === 'ch') { | ||
hostArguments = '-Intl-'; | ||
source = 'print(typeof Intl === "undefined");'; | ||
} | ||
if (type === 'd8') { | ||
hostArguments = '--expose_gc'; | ||
source = 'print(typeof gc === "function");'; | ||
} | ||
if (type === 'jsc') { | ||
hostArguments = '--useWebAssembly=true'; | ||
source = 'print(typeof WebAssembly === "function");'; | ||
} | ||
if (type === 'jsshell') { | ||
hostArguments = '--no-wasm'; | ||
source = 'print(typeof WebAssembly === "undefined");'; | ||
} | ||
if (type === 'node') { | ||
hostArguments = '--expose_gc'; | ||
source = 'print(typeof gc === "function");'; | ||
} | ||
return runify.createAgent(type, Object.assign({ hostArguments }, options)) | ||
.then(a => { | ||
agent = a; | ||
return agent.evalScript(source) | ||
.then(result => { | ||
assert.equal(result.stdout.trim(), 'true'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
// mostly this test shouldn't hang (if it hangs, it's a bug) | ||
it('can kill infinite loops', function () { | ||
var resultP = agent.evalScript(`while (true) { }; print(2);`); | ||
return timeout(100).then(_ => { | ||
var stopP = agent.stop(); | ||
describe('`shortName` option', function () { | ||
it('allows custom shortNames', function() { | ||
const withShortName = Object.assign({ shortName: '$testing' }, options); | ||
return runify.createAgent(type, withShortName).then(agent => { | ||
var p = agent.evalScript('$testing.evalScript("print(1)")').then(result => { | ||
assert(result.error === null, 'no error'); | ||
assert.equal(result.stdout.indexOf('1'), 0); | ||
}); | ||
return Promise.all([resultP, stopP]); | ||
}).then(record => { | ||
const result = record[0]; | ||
assert(!result.stdout.match(/2/), 'Unexpected stdout: ' + result.stdout); | ||
}) | ||
}) | ||
p.catch(function() {}).then(() => agent.destroy()); | ||
return p; | ||
}); | ||
}); | ||
}); | ||
describe('`transform` option', function () { | ||
let agent; | ||
function transform(x) { return `print("${x}")`; } | ||
before(function() { | ||
let withTransform = Object.assign({ transform }, options); | ||
return runify.createAgent(type, withTransform).then(a => agent = a); | ||
}); | ||
after(function() { | ||
return agent.destroy(); | ||
}); | ||
it('runs transforms', function () { | ||
return agent.evalScript('foo').then(function(result) { | ||
assert(result.stdout.match(/^foo\r?\n/), 'Unexpected stdout: ' + result.stdout); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 5 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
318288754
118
1700
180
19