dcp-client
Version:
Core libraries for accessing DCP network
86 lines (77 loc) • 3.04 kB
JavaScript
/**
* @file globalPolyfillHelper.js
*
* Helper file for tests of scripts in libexec/sandbox. Most of the scripts assume
* some specific global symbols exist, so this script polyfills most of them. Depending on
* the scripts being tested, more polyfills may be required, which should be implemented
* in the individual test files. This file also executes the scripts provided in the global scope.
*
* @author Ryan Saweczko, ryansaweczko@kingsds.network
* @date January 2022
*/
const fs = require('fs');
/**
* Initializes the global scope by evaluating a list of files. Typically,
* sandbox initialization files to setup necessary symbols to run test.
*
* Accepts a callback to make spying on post messages easier for test
* assertions.
*
* @param {string[]} files - A list of files to execute in the global scope.
* @param {(message: object) => void} [outputTesting] - Callback that receives post messages.
*/
exports.init = function init(files, outputTesting)
{
let code = ''
for (const file of files)
{
const fd = fs.openSync(file, 'r');
code += fs.readFileSync(fd, 'utf-8') + '\n';
fs.closeSync(fd);
}
// The node worker injects several symbols into the context of the evaluator when it
// is started. These symbols are expected to exist on the global object within the evaluator.
// Emulate the expected global symbols that are most commonly used.
self = global;
global.KVIN = require('kvin');
global.performance = { now: Date.now };
const unmarshal = KVIN.unmarshal;
// postMessage is:
// a) expected to be a symbol in the evaluator
// b) the method almost always used to get information out of the evaluator.
// for this purpose, a callback function should be defined in each test to check
// whatever desired functionality works.
// eslint-disable-next-line vars-on-top
global.postMessage = (line) =>
{
line = unmarshal(line)
if (typeof outputTesting === 'function')
outputTesting(line);
}
// Simulate die with process.exit
global.die = process.exit
// Very, very, very badly created event listener implementation - but suits the needs
const eventsListening = {}
global.addEventListener = (event,callback) =>
{
if (!eventsListening[event])
eventsListening[event] = [];
eventsListening[event].push(callback)
}
global.emitEvent = (event, data) =>
{
if (eventsListening[event])
for (let cb of eventsListening[event])
cb.call(null, data);
}
global.removeEventListener = (event, listener) =>
{
const listenerIdx = eventsListening[event].indexOf(listener);
eventsListening[event].splice(listenerIdx, 1);
}
const indirect = eval;
indirect(code);
// At this point a very primitive version of the evaluator exists - all global symbols defined in
// by the supplied evaluator scripts 'files' exist/are overwritten in the global scope.
// Tests can now use such symbols, or event listeners that would be set up by the files to run tests over them.
}