mirror of https://github.com/embarklabs/embark.git
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:
parent
756a916428
commit
eb4da28a61
|
@ -3,6 +3,7 @@ const fs = require('../../fs');
|
||||||
|
|
||||||
class CodeRunner {
|
class CodeRunner {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
this.ready = false;
|
||||||
this.config = options.config;
|
this.config = options.config;
|
||||||
this.plugins = options.plugins;
|
this.plugins = options.plugins;
|
||||||
this.logger = options.logger;
|
this.logger = options.logger;
|
||||||
|
@ -38,6 +39,7 @@ class CodeRunner {
|
||||||
this.registerEvents();
|
this.registerEvents();
|
||||||
this.registerCommands();
|
this.registerCommands();
|
||||||
this.events.emit('runcode:ready');
|
this.events.emit('runcode:ready');
|
||||||
|
this.ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerIpcEvents() {
|
registerIpcEvents() {
|
||||||
|
@ -74,6 +76,23 @@ class CodeRunner {
|
||||||
cb(this.vm.options.sandbox);
|
cb(this.vm.options.sandbox);
|
||||||
});
|
});
|
||||||
this.events.setCommandHandler('runcode:eval', this.evalCode.bind(this));
|
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 = () => {}) {
|
registerVar(varName, code, toRecord = true, cb = () => {}) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ class TestRunner {
|
||||||
this.fs = embark.fs;
|
this.fs = embark.fs;
|
||||||
this.ipc = options.ipc;
|
this.ipc = options.ipc;
|
||||||
this.runResults = [];
|
this.runResults = [];
|
||||||
|
this.embarkjs = null;
|
||||||
|
|
||||||
this.events.setCommandHandler('tests:run', (options, callback) => {
|
this.events.setCommandHandler('tests:run', (options, callback) => {
|
||||||
this.run(options, callback);
|
this.run(options, callback);
|
||||||
|
@ -145,10 +146,10 @@ class TestRunner {
|
||||||
|
|
||||||
runJSTests(files, options, cb) {
|
runJSTests(files, options, cb) {
|
||||||
const self = this;
|
const self = this;
|
||||||
async.waterfall([
|
|
||||||
function setupGlobalNamespace(next) {
|
|
||||||
const test = new Test({loglevel: options.loglevel, node: options.node, events: self.events, logger: self.logger,
|
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});
|
config: self.embark.config, ipc: self.ipc, coverage: options.coverage, inProcess: options.inProcess});
|
||||||
|
async.waterfall([
|
||||||
|
function setupGlobalNamespace(next) {
|
||||||
global.embark = test;
|
global.embark = test;
|
||||||
global.assert = assert;
|
global.assert = assert;
|
||||||
global.config = test.config.bind(test);
|
global.config = test.config.bind(test);
|
||||||
|
@ -162,20 +163,27 @@ class TestRunner {
|
||||||
global.deployAll = deprecatedWarning;
|
global.deployAll = deprecatedWarning;
|
||||||
global.EmbarkSpec = {};
|
global.EmbarkSpec = {};
|
||||||
global.EmbarkSpec.deployAll = deprecatedWarning;
|
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');`
|
// Override require to enable `require('Embark/contracts/contractName');`
|
||||||
const Module = require('module');
|
const Module = require('module');
|
||||||
const originalRequire = require('module').prototype.require;
|
const originalRequire = require('module').prototype.require;
|
||||||
Module.prototype.require = function (requireName) {
|
Module.prototype.require = function (requireName) {
|
||||||
|
if (requireName.startsWith('Embark/EmbarkJS')) {
|
||||||
|
return self.embarkjs;
|
||||||
|
}
|
||||||
if (requireName.startsWith('Embark')) {
|
if (requireName.startsWith('Embark')) {
|
||||||
return test.require(...arguments);
|
return test.require(...arguments);
|
||||||
}
|
}
|
||||||
return originalRequire.apply(this, arguments);
|
return originalRequire.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
next();
|
||||||
global.contract = function (describeName, callback) {
|
},
|
||||||
return Mocha.describe(describeName, callback);
|
function initTest(next) {
|
||||||
};
|
|
||||||
|
|
||||||
test.init((err) => {
|
test.init((err) => {
|
||||||
next(err, files);
|
next(err, files);
|
||||||
|
@ -200,9 +208,13 @@ class TestRunner {
|
||||||
global.config({});
|
global.config({});
|
||||||
}
|
}
|
||||||
global.embark.onReady((err) => {
|
global.embark.onReady((err) => {
|
||||||
|
if(err) return done(err);
|
||||||
|
self.events.request('runcode:eval', 'EmbarkJS', (err, embarkjs) => {
|
||||||
|
self.embarkjs = embarkjs;
|
||||||
done(err);
|
done(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
mocha.run(function (fails) {
|
mocha.run(function (fails) {
|
||||||
mocha.suite.removeAllListeners();
|
mocha.suite.removeAllListeners();
|
||||||
// Mocha prints the error already
|
// Mocha prints the error already
|
||||||
|
|
|
@ -120,10 +120,16 @@ class SolcTest extends Test {
|
||||||
methodIdentifiers: contract.functionHashes
|
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);
|
self._prettyPrint.bind(self), _callback);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
fns.push(fn);
|
fns.push(fn);
|
||||||
|
|
||||||
});
|
});
|
||||||
async.series(fns, next);
|
async.series(fns, next);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,10 @@ import * as utilsContractsConfig from "../../utils/contractsConfig";
|
||||||
|
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const AccountParser = require('../../utils/accountParser');
|
const AccountParser = require('../../utils/accountParser');
|
||||||
const EmbarkJS = require('embarkjs');
|
|
||||||
const utils = require('../../utils/utils');
|
const utils = require('../../utils/utils');
|
||||||
const constants = require('../../constants');
|
const constants = require('../../constants');
|
||||||
const web3Utils = require('web3-utils');
|
const web3Utils = require('web3-utils');
|
||||||
const VM = require('../../core/modules/coderunner/vm');
|
const EmbarkJS = require('embarkjs');
|
||||||
const Web3 = require('web3');
|
|
||||||
const IpfsApi = require("ipfs-api");
|
|
||||||
|
|
||||||
const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';
|
const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';
|
||||||
|
|
||||||
|
@ -32,6 +29,7 @@ class Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
init(callback) {
|
init(callback) {
|
||||||
|
this.events.request('runcode:ready', () => {
|
||||||
this.gasLimit = constants.tests.gasLimit;
|
this.gasLimit = constants.tests.gasLimit;
|
||||||
this.events.request('deploy:setGasLimit', this.gasLimit);
|
this.events.request('deploy:setGasLimit', this.gasLimit);
|
||||||
const waitingForReady = setTimeout(() => {
|
const waitingForReady = setTimeout(() => {
|
||||||
|
@ -51,6 +49,7 @@ class Test {
|
||||||
}
|
}
|
||||||
this.connectToIpcNode(callback);
|
this.connectToIpcNode(callback);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
connectToIpcNode(cb) {
|
connectToIpcNode(cb) {
|
||||||
|
@ -229,7 +228,6 @@ class Test {
|
||||||
}
|
}
|
||||||
self.ready = true;
|
self.ready = true;
|
||||||
self.error = false;
|
self.error = false;
|
||||||
self.events.emit('tests:ready');
|
|
||||||
next(null, accounts);
|
next(null, accounts);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -243,31 +241,16 @@ class Test {
|
||||||
// TODO Do not exit in case of not a normal run (eg after a change)
|
// TODO Do not exit in case of not a normal run (eg after a change)
|
||||||
if (!self.options.inProcess) process.exit(1);
|
if (!self.options.inProcess) process.exit(1);
|
||||||
}
|
}
|
||||||
|
self.events.emit('tests:ready');
|
||||||
callback(null, accounts);
|
callback(null, accounts);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resetEmbarkJS(cb) {
|
resetEmbarkJS(cb) {
|
||||||
this.events.request('blockchain:get', (web3) => {
|
this.events.request('blockchain:get', (web3) => {
|
||||||
|
// global web3 used in the tests, not in the vm
|
||||||
global.web3 = web3;
|
global.web3 = web3;
|
||||||
this.vm = new VM({
|
this.events.request("runcode:embarkjs:reset", cb);
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +322,14 @@ class Test {
|
||||||
|
|
||||||
const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0];
|
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);
|
Object.setPrototypeOf(self.contracts[contract.className], newContract);
|
||||||
|
|
||||||
eachCb();
|
eachCb();
|
||||||
|
@ -359,7 +349,7 @@ class Test {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static getWeb3Contract(contract, web3) {
|
getWeb3Contract(contract, web3, cb) {
|
||||||
const newContract = new EmbarkJS.Blockchain.Contract({
|
const newContract = new EmbarkJS.Blockchain.Contract({
|
||||||
abi: contract.abiDefinition,
|
abi: contract.abiDefinition,
|
||||||
address: contract.deployedAddress,
|
address: contract.deployedAddress,
|
||||||
|
@ -378,11 +368,11 @@ class Test {
|
||||||
newContract.options.gas = constants.tests.gasLimit;
|
newContract.options.gas = constants.tests.gasLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
return newContract;
|
cb(null, newContract);
|
||||||
}
|
}
|
||||||
|
|
||||||
require(path) {
|
require(path) {
|
||||||
const [contractsPrefix, embarkJSPrefix] = ['Embark/contracts/', 'Embark/EmbarkJS'];
|
const contractsPrefix = 'Embark/contracts/';
|
||||||
|
|
||||||
// Contract require
|
// Contract require
|
||||||
if (path.startsWith(contractsPrefix)) {
|
if (path.startsWith(contractsPrefix)) {
|
||||||
|
@ -397,11 +387,6 @@ class Test {
|
||||||
return newContract;
|
return newContract;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmbarkJS require
|
|
||||||
if (path.startsWith(embarkJSPrefix)) {
|
|
||||||
return EmbarkJS;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(__('Unknown module %s', path));
|
throw new Error(__('Unknown module %s', path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
const web3Connector = {};
|
const web3Connector = {};
|
||||||
|
|
||||||
web3Connector.init = function(_config) {
|
web3Connector.init = function(_config) {
|
||||||
|
global.web3 = config.web3 || global.web3;
|
||||||
// Check if the global web3 object uses the old web3 (0.x)
|
// Check if the global web3 object uses the old web3 (0.x)
|
||||||
if (global.web3 && typeof global.web3.version !== 'string') {
|
if (global.web3 && typeof global.web3.version !== 'string') {
|
||||||
// If so, use a new instance using 1.0, but use its provider
|
// If so, use a new instance using 1.0, but use its provider
|
||||||
|
|
Loading…
Reference in New Issue