fix(@embark/tests): Tests exiting early

Tests were exiting early and Mocha was reporting an exit code of 0. This allowed CI to complete as if the tests were successful.

Change `compiler:contracts` event request to `compiler:contracts:compile` and update documentation. Because the `compiler:contracts` event didn’t exist, this test was silently failing.

Update the `TestEvents` mock object to allow passing of parameters to an event that is not a callback.

Add unit tests to test for contracts loaded via node_modules.

1. This PR contains a change where any contracts loaded from node_modules will be imported in to `.embark/contracts/node_modules`. Previously, these contracts were loaded in to `.embark/node_modules` (with the `/contracts`).
This commit is contained in:
emizzle 2019-12-05 22:05:31 +11:00 committed by Iuri Matias
parent ad26533f4a
commit acd1d72f2d
18 changed files with 316 additions and 63 deletions

View File

@ -170,8 +170,9 @@ export function getExternalContractUrl(file: string, providerUrl: string) {
} else {
return null;
}
const match = url.match(
/\.[a-z]+\/([-a-zA-Z0-9@:%_+.~#?&\/=]+)/,
const urlToMatch = providerUrl && providerUrl.includes("localhost") ? url.replace(providerUrl, "") : url;
const match = urlToMatch.match(
/(?:\.[a-z]+|localhost:[0-9]+)\/([-a-zA-Z0-9@:%_+.~#?&\/=]+)/,
);
return {
filePath: HTTP_CONTRACTS_DIRECTORY + (match !== null ? match[1] : ''),

View File

@ -72,7 +72,7 @@ const buildNewFile = (file: File, importPath: string) => {
// imported from node_modules, ie import "@aragon/os/contracts/acl/ACL.sol"
if (isUnresolvedNodeModule(importPath)) {
from = resolve(importPath);
to = importPath.includes(dappPath(".embark")) ? importPath : dappPath(".embark", "node_modules", importPath);
to = importPath.includes(dappPath(".embark")) ? importPath : dappPath(".embark", "contracts", "node_modules", importPath);
if (from !== to) {
fs.copySync(from, to);
}

View File

@ -182,6 +182,7 @@
"embark-solo": "^5.0.0-alpha.2",
"embark-test-contract-0": "0.0.2",
"embark-test-contract-1": "0.0.1",
"embark-testing": "^5.0.0-alpha.1",
"eslint": "5.7.0",
"npm-run-all": "4.1.5",
"nyc": "13.1.0",

View File

@ -19,6 +19,9 @@ describe('embark.Config', function () {
"enabled": true,
"client": "geth",
"proxy": true,
"clientConfig": {
"miningMode": "dev"
},
"datadir": ".embark/myenv/datadir",
"rpcHost": "localhost",
"rpcPort": 8545,
@ -53,6 +56,9 @@ describe('embark.Config', function () {
"enabled": true,
"client": "geth",
"proxy": true,
"clientConfig": {
"miningMode": "dev"
},
"datadir": ".embark/unitenv/datadir",
"rpcHost": "localhost",
"rpcPort": 8545,
@ -103,6 +109,9 @@ describe('embark.Config', function () {
"enabled": true,
"client": "geth",
"proxy": true,
"clientConfig": {
"miningMode": "dev"
},
"datadir": ".embark/unitlessenv/datadir",
"rpcHost": "localhost",
"rpcPort": 8545,
@ -153,6 +162,9 @@ describe('embark.Config', function () {
"enabled": true,
"client": "geth",
"proxy": true,
"clientConfig": {
"miningMode": "dev"
},
"datadir": ".embark/extNetwork/datadir",
"rpcHost": "localhost",
"rpcPort": 8545,
@ -172,7 +184,6 @@ describe('embark.Config', function () {
"nodiscover": true,
"maxpeers": 0,
"simulatorBlocktime": 0,
"miningMode": "dev",
"targetGasLimit": 8000000,
"endpoint": "http://mynetwork.com"
};
@ -195,7 +206,7 @@ describe('embark.Config', function () {
config.loadContractsConfigFile();
let expectedConfig = {
versions: {solc: '0.5.0'},
dappConnection: ['$WEB3', 'localhost:8545'],
dappConnection: ['$WEB3', 'ws://localhost:8546', 'localhost:8545'],
dappAutoEnable: true,
"gas": "400000",
"strategy": "implicit",
@ -217,7 +228,7 @@ describe('embark.Config', function () {
it('should replace occurrences of `0x0` with full zero addresses', () => {
let expectedConfig = {
versions: {solc: '0.5.0'},
dappConnection: ['$WEB3', 'localhost:8545'],
dappConnection: ['$WEB3', 'ws://localhost:8546', 'localhost:8545'],
dappAutoEnable: true,
"gas": "auto",
"strategy": "implicit",

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,5 @@
pragma solidity ^0.5.0;
import "embark-test-contract-0/recursive_test_3.sol";
contract SimpleStorageRecursive2 {
uint public storedData;

View File

@ -0,0 +1,19 @@
pragma solidity ^0.5.0;
import "embark-test-contract-0/recursive_test_3.sol";
contract SimpleStorageRecursiveNodeModules {
uint public storedData;
constructor(uint initialValue) public {
storedData = initialValue;
}
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint retVal) {
return storedData;
}
}

View File

@ -1,21 +1,32 @@
/*globals describe, it*/
/*globals describe, it, before*/
const { dappPath, File, joinPath, setUpEnv, Types } = require('embark-utils');
const { expect } = require("chai");
const fs = require("fs-extra");
const { HttpMockServer } = require("embark-testing");
setUpEnv(joinPath(__dirname, '../../'));
let connectionString;
describe('embark.File', function () {
describe('Read file contents', function () {
before('set up mock HTTP server', async () => {
const server = new HttpMockServer.default();
connectionString = await server.init();
server.addRoute({
path: "/simple_storage.sol",
result: "great success!"
});
});
it('should be able to download a file when type is "http"', async () => {
const file = new File({externalUrl: 'https://raw.githubusercontent.com/embark-framework/embark/master/dapps/tests/app/app/contracts/simple_storage.sol', type: Types.http});
const file = new File({ externalUrl: `${connectionString}/simple_storage.sol`, type: Types.http });
const content = await file.content;
expect(content).to.be.ok; //eslint-disable-line
expect(content).to.equal("great success!"); //eslint-disable-line
});
it('should be able to read a file when type is "dappFile"', async () => {
const file = new File({path: dappPath('contracts/recursive_test_0.sol'), type: Types.dappFile});
const file = new File({ path: dappPath('contracts/recursive_test_0.sol'), type: Types.dappFile });
const content = await file.content;
const contentFromFileSystem = fs.readFileSync(dappPath("contracts/recursive_test_0.sol")).toString();
@ -23,14 +34,16 @@ describe('embark.File', function () {
});
it('should be able to execute a resolver when type is "custom"', async () => {
const file = new File({path: dappPath('contracts/recursive_test_0.sol'), type: Types.custom, resolver: (callback) => {
callback("test");
}});
const file = new File({
path: dappPath('contracts/recursive_test_0.sol'), type: Types.custom, resolver: (callback) => {
callback("test");
}
});
expect(await file.content).to.equal("test");
});
it('should be able to read a file when type is "embarkInternal"', async () => {
const file = new File({path: 'test/contracts/recursive_test_0.sol', type: Types.embarkInternal});
const file = new File({ path: 'test/contracts/recursive_test_0.sol', type: Types.embarkInternal });
const content = await file.content;
const contentFromFileSystem = fs.readFileSync(dappPath("contracts/recursive_test_0.sol")).toString();

View File

@ -59,7 +59,7 @@ describe('embark.Compiler', function() {
const compiler = new Compiler(embarkObject, {plugins: plugins});
it("should return aggregated result", (done) => {
events.request("compiler:contracts", [
events.request("compiler:contracts:compile", [
readFile('contracts/simple_storage.sol'),
readFile('contracts/token.sol'),
readFile('contracts/erc20.vy')

View File

@ -1,15 +1,82 @@
/*globals describe, it, before*/
const { dappPath, File, Types, prepareForCompilation } = require('embark-utils');
const path = require("path");
const {expect} = require("chai");
const { expect } = require("chai");
const fsNode = require("fs");
const { HttpMockServer } = require("embark-testing");
let file, content;
let file, content, connectionString;
const routes = [
{
path: "/recursive_test_0.sol",
result: `pragma solidity ^0.5.0;
import "./recursive_test_1.sol";
contract SimpleStorageRecursive0 {
uint public storedData;
constructor (uint initialValue) public {
storedData = initialValue;
}
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint retVal) {
return storedData;
}
}`
},
{
path: "/recursive_test_1.sol",
result: `pragma solidity ^0.5.0;
import "./recursive_test_2.sol";
contract SimpleStorageRecursive1 {
uint public storedData;
constructor(uint initialValue) public {
storedData = initialValue;
}
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint retVal) {
return storedData;
}
}`
},
{
path: "/recursive_test_2.sol",
result: `pragma solidity ^0.5.0;
contract SimpleStorageRecursive2 {
uint public storedData;
constructor(uint initialValue) public {
storedData = initialValue;
}
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint retVal) {
return storedData;
}
}`
}
];
describe('embark.RemapImports', function () {
describe('Import remappings from local file', function () {
before('do the remappings', async () => {
file = new File({path: 'contracts/recursive_test_0.sol', type: Types.dappFile});
file = new File({ path: 'contracts/recursive_test_0.sol', type: Types.dappFile });
content = await prepareForCompilation(file);
});
@ -22,14 +89,6 @@ describe('embark.RemapImports', function () {
prefix: "./recursive_test_2.sol",
target: path.normalize(dappPath(".embark/contracts/recursive_test_2.sol"))
});
expect(file.importRemappings[2]).to.deep.equal({
prefix: "embark-test-contract-0/recursive_test_3.sol",
target: path.normalize(dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol"))
});
expect(file.importRemappings[3]).to.deep.equal({
prefix: "embark-test-contract-1/recursive_test_4.sol",
target: path.normalize(dappPath(".embark/node_modules/embark-test-contract-1/recursive_test_4.sol"))
});
done();
});
@ -45,14 +104,6 @@ describe('embark.RemapImports', function () {
expect(contractFromFilesystem).to.not.contain("./recursive_test_2.sol");
expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/recursive_test_2.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/recursive_test_2.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-0/recursive_test_3.sol\"");
expect(contractFromFilesystem).to.contain(`import "${path.normalize(dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol")).replace(/\\/g, "/")}"`);
contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-1/recursive_test_4.sol\"");
expect(contractFromFilesystem).to.contain(`import "${path.normalize(dappPath(".embark/node_modules/embark-test-contract-1/recursive_test_4.sol")).replace(/\\/g, "/")}"`);
done();
});
@ -60,41 +111,72 @@ describe('embark.RemapImports', function () {
describe('Import remappings from external URL', function () {
before('do the external HTTP contract remappings', async () => {
file = new File({externalUrl: 'https://github.com/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_0.sol', type: Types.http});
const server = new HttpMockServer.default();
connectionString = await server.init();
routes.forEach(route => {
server.addRoute(route);
});
file = new File({ externalUrl: `${connectionString}/recursive_test_0.sol`, type: Types.http });
content = await prepareForCompilation(file);
});
it("should find and add remappings for all recursive imports", (done) => {
expect(file.importRemappings[0]).to.deep.equal({
prefix: "./recursive_test_1.sol",
target: path.normalize(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol"))
target: path.normalize(dappPath(".embark/contracts/recursive_test_1.sol"))
});
expect(file.importRemappings[1]).to.deep.equal({
prefix: "./recursive_test_2.sol",
target: path.normalize(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_2.sol"))
});
expect(file.importRemappings[2]).to.deep.equal({
prefix: "embark-test-contract-0/recursive_test_3.sol",
target: path.normalize(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/embark-test-contract-0/recursive_test_3.sol"))
target: path.normalize(dappPath(".embark/contracts/recursive_test_2.sol"))
});
done();
});
it("should update the contract content to use the remapped imports", function (done) {
expect(content).to.not.contain("./recursive_test_1.sol");
expect(content).to.contain(path.normalize(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
expect(content).to.contain(path.normalize(".embark/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
let contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_0.sol")).toString();
let contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/recursive_test_0.sol")).toString();
expect(contractFromFilesystem).to.not.contain("./recursive_test_1.sol");
expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol")).toString();
contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/recursive_test_1.sol")).toString();
expect(contractFromFilesystem).to.not.contain("./recursive_test_2.sol");
expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_2.sol").replace(/\\/g, "/"));
expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/recursive_test_2.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_2.sol")).toString();
done();
});
});
describe('Import remappings from node_modules', function () {
before('do the node_modules contract remappings', async () => {
file = new File({ path: 'contracts/recursive_test_node_modules.sol', type: Types.dappFile });
content = await prepareForCompilation(file);
});
it("should find and add remappings for all recursive imports", (done) => {
expect(file.importRemappings[0]).to.deep.equal({
prefix: "embark-test-contract-0/recursive_test_3.sol",
target: path.normalize(dappPath(".embark/contracts/node_modules/embark-test-contract-0/recursive_test_3.sol"))
});
expect(file.importRemappings[1]).to.deep.equal({
prefix: "embark-test-contract-1/recursive_test_4.sol",
target: path.normalize(dappPath(".embark/contracts/node_modules/embark-test-contract-1/recursive_test_4.sol"))
});
done();
});
it("should update the contract content to use the remapped imports", function (done) {
expect(content).to.not.contain("./embark-test-contract-0/recursive_test_3.sol");
expect(content).to.contain(path.normalize(".embark/contracts/node_modules/embark-test-contract-0/recursive_test_3.sol").replace(/\\/g, "/"));
let contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/recursive_test_node_modules.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-0/recursive_test_3.sol\"");
expect(contractFromFilesystem).to.contain(`import "${path.normalize(dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/embark-test-contract-0/recursive_test_3.sol")).replace(/\\/g, "/")}"`);
expect(contractFromFilesystem).to.contain(`import "${path.normalize(dappPath(".embark/contracts/node_modules/embark-test-contract-0/recursive_test_3.sol")).replace(/\\/g, "/")}"`);
contractFromFilesystem = fsNode.readFileSync(dappPath(".embark/contracts/node_modules/embark-test-contract-0/recursive_test_3.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-1/recursive_test_4.sol\"");
expect(contractFromFilesystem).to.contain(`import "${path.normalize(dappPath(".embark/contracts/node_modules/embark-test-contract-1/recursive_test_4.sol")).replace(/\\/g, "/")}"`);
done();
});

View File

@ -16,7 +16,9 @@ let generateApiObject = function() {
var TestEvents = {
request: (cmd, cb) => {
cb(solcVersion);
if (typeof cb === "function") {
cb(solcVersion);
}
},
emit: (_ev, _data) => {}
};

View File

@ -2,14 +2,16 @@
const assert = require('assert');
const sinon = require('sinon');
const path = require('path');
import { ProcessLauncher, TestLogger } from 'embark-core';
import { ProcessLauncher, TestLogger, Events } from 'embark-core';
let logger = new TestLogger({});
const events = new Events();
let embarkObj = {
logger: logger,
registerAPICall: () => {}
}
};
describe('ProcessWrapper', () => {
let processLauncher;
@ -19,7 +21,8 @@ describe('ProcessWrapper', () => {
processLauncher = new ProcessLauncher({
embark: embarkObj,
logger: logger,
modulePath: path.join(__dirname, 'test.js')
modulePath: path.join(__dirname, 'test.js'),
events
});
});

View File

@ -8,7 +8,7 @@ returns the aggregated compilation result.
## API
**command: `compiler:contracts`**
**command: `compiler:contracts:compile`**
arguments:
@ -40,7 +40,7 @@ example:
import { File } from 'src/lib/core/file.js';
const contractFiles = [(new File({path: "simplestorage.sol", type: "custom", resolver: (cb) => { return cb(".. contract code...") }}))];
embark.events.request("compiler:contracts", contractFiles, {}, (err, compiledObject) => {
embark.events.request("compiler:contracts:compile", contractFiles, {}, (err, compiledObject) => {
})
```

View File

@ -31,17 +31,23 @@
"_build": "npm run solo -- build",
"ci": "npm run qa",
"clean": "npm run reset",
"lint": "eslint src/",
"qa": "npm-run-all lint _build",
"lint": "npm-run-all lint:*",
"lint:js": "eslint src/",
"lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
"qa": "npm-run-all lint typecheck _build",
"reset": "npx rimraf dist embark-*.tgz package",
"solo": "embark-solo",
"test": "jest"
"typecheck": "tsc",
"test": "jest",
"watch": "run-p watch:*",
"watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
},
"eslintConfig": {
"extends": "../../../.eslintrc.json"
},
"dependencies": {
"@babel/runtime-corejs3": "7.7.4",
"async": "2.6.1",
"core-js": "3.4.3",
"refute": "1.0.2",
"sinon": "7.4.2"
@ -55,7 +61,9 @@
"jest": "24.9.0",
"lodash.clonedeep": "4.5.0",
"npm-run-all": "4.1.5",
"rimraf": "2.6.3"
"rimraf": "2.6.3",
"tslint": "5.16.0",
"typescript": "3.6.3"
},
"jest": {
"collectCoverage": true,
@ -77,4 +85,4 @@
"npm": ">=6.11.3",
"yarn": ">=1.19.1"
}
}
}

View File

@ -0,0 +1,95 @@
import { string } from "prop-types";
import http from "http";
import net from "net";
import { waterfall } from "async";
import { promisify } from 'util';
enum Method {
GET,
POST
}
export interface Route {
path: string;
result: string;
statusCode: number;
method?: Method;
}
export default class HttpMockServer {
private routes: Route[] = [];
private server: http.Server;
private sock: net.Server;
private connectionString: string = "";
constructor() {
this.sock = net.createServer();
this.server = http.createServer(this.handleRequestWrapper.bind(this));
}
public init() {
return new Promise((resolve, reject) => {
let port;
waterfall([
cb => { this.sock.listen(0, cb); },
cb => {
const address = this.sock.address() as net.AddressInfo;
if (!address) {
cb("Could not get an address from the socket");
}
port = address.port;
cb();
},
cb => { this.sock.close(cb); },
cb => { this.server.listen(port, '127.0.0.1', () => cb()); }
], (err) => {
if (err) {
return reject(err);
}
this.connectionString = `http://localhost:${port}`;
resolve(this.connectionString);
});
});
}
private handleRequestWrapper(req: http.IncomingMessage, res: http.ServerResponse) {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
let jsonBody = {};
if (body) {
jsonBody = JSON.parse(body);
}
this.handleRequest(req.url, jsonBody, res);
});
}
protected handleRequest(path: string | undefined = "", req: object, res: http.ServerResponse) {
const route = this.routes[path];
if (!route) {
res.statusCode = 404;
return res.end();
}
res.writeHead(route.statusCode, {
'Content-Length': Buffer.byteLength(route.result),
'Content-Type': 'application/json'
});
res.end(route.result);
}
public addRoute(route: Route) {
if (!route.statusCode) {
route.statusCode = 200;
}
if (!route.method) {
route.method = Method.GET;
}
this.routes[route.path] = route;
}
public teardown() {
this.routes = [];
}
}

View File

@ -1,6 +1,7 @@
const Embark = require('./embark');
const Events = require('./events');
const Plugins = require('./plugin');
const HttpMockServer = require('./httpServer');
const fakeEmbark = (config) => {
const events = new Events();
@ -17,6 +18,7 @@ module.exports = {
Embark,
Events,
Plugins,
HttpMockServer,
fakeEmbark
};

View File

@ -0,0 +1,4 @@
{
"extends": "../../../tsconfig.json",
"include": ["src/**/*"]
}

View File

@ -0,0 +1,3 @@
{
"extends": "../../../tslint.json"
}