fix(@embark/core): Fix tests for shim/monorepo

When embark was running as module inside the dapp’s `node_modules`, the tests were failing due to several issues:
1. `web3` was not being set in the global namespace of vm2. `EmbarkJS.Blockchain.setProvider` was therefore failing because it relies on `global.web3` to be set. I guess somehow this works when the test app was running in a child tree of the executing program. maybe this is a security feature of vm2, but i’m not sure.
2. `embarkjs` provider code being injected to the vm twice. This really was the initial point of failure, as this piece of code is requiring embarkjs, so i’m assuming, but again not sure, that maybe it was getting a second instance of `EmbarkJS` which did not have it’s providers set up correctly (hence the error with `ENS provider not set`).

Fixes for those issues in this PR:
1. To circumvent the web3 issue, we are now setting `global.web3` for tests only (the global web3 accessible in the tests), and `web3` is now explicitly passed in to `EmbarkJS.Blockchain.setProvider`
2. To fix the `embarkjs` code being called twice, we are not re-injecting this code to the VM during test initialisations
This commit is contained in:
emizzle 2019-01-23 15:57:24 +11:00 committed by Iuri Matias
parent 756a916428
commit eb4da28a61
5 changed files with 83 additions and 60 deletions

View File

@ -3,6 +3,7 @@ const fs = require('../../fs');
class CodeRunner {
constructor(options) {
this.ready = false;
this.config = options.config;
this.plugins = options.plugins;
this.logger = options.logger;
@ -38,6 +39,7 @@ class CodeRunner {
this.registerEvents();
this.registerCommands();
this.events.emit('runcode:ready');
this.ready = true;
}
registerIpcEvents() {
@ -74,6 +76,23 @@ class CodeRunner {
cb(this.vm.options.sandbox);
});
this.events.setCommandHandler('runcode:eval', this.evalCode.bind(this));
this.events.setCommandHandler('runcode:ready', (cb) => {
if (this.ready) {
return cb();
}
this.events.once("runcode:ready", cb);
});
this.events.setCommandHandler('runcode:embarkjs:reset', this.resetEmbarkJS.bind(this));
}
resetEmbarkJS(cb) {
this.events.request('blockchain:get', (web3) => {
this.events.emit("runcode:register", "web3", web3, false, () => {
this.events.request("code-generator:embarkjs:init-provider-code", async (code) => {
await this.evalCode(code, cb, true);
});
});
});
}
registerVar(varName, code, toRecord = true, cb = () => {}) {

View File

@ -16,6 +16,7 @@ class TestRunner {
this.fs = embark.fs;
this.ipc = options.ipc;
this.runResults = [];
this.embarkjs = null;
this.events.setCommandHandler('tests:run', (options, callback) => {
this.run(options, callback);
@ -145,10 +146,10 @@ class TestRunner {
runJSTests(files, options, cb) {
const self = this;
async.waterfall([
function setupGlobalNamespace(next) {
const test = new Test({loglevel: options.loglevel, node: options.node, events: self.events, logger: self.logger,
config: self.embark.config, ipc: self.ipc, coverage: options.coverage, inProcess: options.inProcess});
async.waterfall([
function setupGlobalNamespace(next) {
global.embark = test;
global.assert = assert;
global.config = test.config.bind(test);
@ -162,20 +163,27 @@ class TestRunner {
global.deployAll = deprecatedWarning;
global.EmbarkSpec = {};
global.EmbarkSpec.deployAll = deprecatedWarning;
global.contract = function (describeName, callback) {
return Mocha.describe(describeName, callback);
};
next();
},
function overrideRequire (next) {
// Override require to enable `require('Embark/contracts/contractName');`
const Module = require('module');
const originalRequire = require('module').prototype.require;
Module.prototype.require = function (requireName) {
if (requireName.startsWith('Embark/EmbarkJS')) {
return self.embarkjs;
}
if (requireName.startsWith('Embark')) {
return test.require(...arguments);
}
return originalRequire.apply(this, arguments);
};
global.contract = function (describeName, callback) {
return Mocha.describe(describeName, callback);
};
next();
},
function initTest(next) {
test.init((err) => {
next(err, files);
@ -200,9 +208,13 @@ class TestRunner {
global.config({});
}
global.embark.onReady((err) => {
if(err) return done(err);
self.events.request('runcode:eval', 'EmbarkJS', (err, embarkjs) => {
self.embarkjs = embarkjs;
done(err);
});
});
});
mocha.run(function (fails) {
mocha.suite.removeAllListeners();
// Mocha prints the error already

View File

@ -120,10 +120,16 @@ class SolcTest extends Test {
methodIdentifiers: contract.functionHashes
}
};
remixTests.runTest(contract.className, Test.getWeb3Contract(contract, web3), contractDetails, {accounts},
this.getWeb3Contract(contract, web3, (err, web3contract) => {
if(err) {
return _callback(err);
}
remixTests.runTest(contract.className, web3contract, contractDetails, {accounts},
self._prettyPrint.bind(self), _callback);
});
};
fns.push(fn);
});
async.series(fns, next);
}

View File

@ -2,13 +2,10 @@ import * as utilsContractsConfig from "../../utils/contractsConfig";
const async = require('async');
const AccountParser = require('../../utils/accountParser');
const EmbarkJS = require('embarkjs');
const utils = require('../../utils/utils');
const constants = require('../../constants');
const web3Utils = require('web3-utils');
const VM = require('../../core/modules/coderunner/vm');
const Web3 = require('web3');
const IpfsApi = require("ipfs-api");
const EmbarkJS = require('embarkjs');
const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';
@ -32,6 +29,7 @@ class Test {
}
init(callback) {
this.events.request('runcode:ready', () => {
this.gasLimit = constants.tests.gasLimit;
this.events.request('deploy:setGasLimit', this.gasLimit);
const waitingForReady = setTimeout(() => {
@ -51,6 +49,7 @@ class Test {
}
this.connectToIpcNode(callback);
});
});
}
connectToIpcNode(cb) {
@ -229,7 +228,6 @@ class Test {
}
self.ready = true;
self.error = false;
self.events.emit('tests:ready');
next(null, accounts);
});
},
@ -243,31 +241,16 @@ class Test {
// TODO Do not exit in case of not a normal run (eg after a change)
if (!self.options.inProcess) process.exit(1);
}
self.events.emit('tests:ready');
callback(null, accounts);
});
}
resetEmbarkJS(cb) {
this.events.request('blockchain:get', (web3) => {
// global web3 used in the tests, not in the vm
global.web3 = web3;
this.vm = new VM({
sandbox: {
EmbarkJS,
web3: web3,
Web3: Web3,
IpfsApi
}
});
this.events.request("code-generator:embarkjs:provider-code", (code) => {
this.vm.doEval(code, false, (err, _result) => {
if(err) return cb(err);
this.events.request("code-generator:embarkjs:init-provider-code", (code) => {
this.vm.doEval(code, false, (err, _result) => {
cb(err);
});
});
});
});
this.events.request("runcode:embarkjs:reset", cb);
});
}
@ -339,7 +322,14 @@ class Test {
const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0];
const newContract = testContractFactoryPlugin ? testContractFactoryPlugin.testContractFactory(contract, web3) : Test.getWeb3Contract(contract, web3);
if (!testContractFactoryPlugin) {
return self.getWeb3Contract(contract, web3, (err, web3Contract) => {
Object.setPrototypeOf(self.contracts[contract.className], web3Contract);
eachCb();
});
}
const newContract = testContractFactoryPlugin.testContractFactory(contract, web3);
Object.setPrototypeOf(self.contracts[contract.className], newContract);
eachCb();
@ -359,7 +349,7 @@ class Test {
});
}
static getWeb3Contract(contract, web3) {
getWeb3Contract(contract, web3, cb) {
const newContract = new EmbarkJS.Blockchain.Contract({
abi: contract.abiDefinition,
address: contract.deployedAddress,
@ -378,11 +368,11 @@ class Test {
newContract.options.gas = constants.tests.gasLimit;
}
return newContract;
cb(null, newContract);
}
require(path) {
const [contractsPrefix, embarkJSPrefix] = ['Embark/contracts/', 'Embark/EmbarkJS'];
const contractsPrefix = 'Embark/contracts/';
// Contract require
if (path.startsWith(contractsPrefix)) {
@ -397,11 +387,6 @@ class Test {
return newContract;
}
// EmbarkJS require
if (path.startsWith(embarkJSPrefix)) {
return EmbarkJS;
}
throw new Error(__('Unknown module %s', path));
}
}

View File

@ -2,6 +2,7 @@
const web3Connector = {};
web3Connector.init = function(_config) {
global.web3 = config.web3 || global.web3;
// Check if the global web3 object uses the old web3 (0.x)
if (global.web3 && typeof global.web3.version !== 'string') {
// If so, use a new instance using 1.0, but use its provider