truffle
Version:
Truffle - Simple development framework for Ethereum
1,311 lines (1,209 loc) • 54.7 kB
JavaScript
#!/usr/bin/env node
exports.id = 6394;
exports.ids = [6394];
exports.modules = {
/***/ 93622:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const copyArtifactsToTempDir = async config => {
const fse = __webpack_require__(55674);
const OS = __webpack_require__(22037);
const tmp = __webpack_require__(36276);
tmp.setGracefulCleanup();
// Copy all the built files over to a temporary directory, because we
// don't want to save any tests artifacts. Only do this if the build directory
// exists.
const temporaryDirectory = tmp.dirSync({
unsafeCleanup: true,
prefix: "test-"
}).name;
try {
fse.statSync(config.contracts_build_directory);
} catch (_error) {
return { temporaryDirectory };
}
fse.copySync(config.contracts_build_directory, temporaryDirectory);
if (config.runnerOutputOnly !== true) {
config.logger.log("Using network '" + config.network + "'." + OS.EOL);
}
return { temporaryDirectory };
};
module.exports = {
copyArtifactsToTempDir
};
/***/ }),
/***/ 13799:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const determineTestFilesToRun = ({ inputFile, inputArgs = [], config }) => {
const path = __webpack_require__(71017);
const fs = __webpack_require__(57147);
const glob = __webpack_require__(12884);
let filesToRun = [];
if (inputFile) {
filesToRun.push(inputFile);
} else if (inputArgs.length > 0) {
inputArgs.forEach(inputArg => filesToRun.push(inputArg));
}
if (filesToRun.length === 0) {
const directoryContents = glob.sync(
`${config.test_directory}${path.sep}**${path.sep}*`
);
filesToRun =
directoryContents.filter(item => fs.statSync(item).isFile()) || [];
}
return filesToRun.filter(file => {
return file.match(config.test_file_extension_regexp) !== null;
});
};
module.exports = {
determineTestFilesToRun
};
/***/ }),
/***/ 55472:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const colors = __webpack_require__(83196);
const createInTestDebugFunction = function ({
mochaRunner,
compilations,
config
}) {
return async operation => {
if (!config.debug) {
config.logger.log(
`${colors.bold(
"Warning:"
)} Invoked in-test debugger without --debug flag. ` +
`Try: \`truffle test --debug\``
);
return operation;
}
// wrapped inside function so as not to load debugger on every test
const { CLIDebugHook } = __webpack_require__(12834);
const hook = new CLIDebugHook(config, compilations, mochaRunner);
return await hook.debug(operation);
};
};
const prepareConfigAndRunTests = ({ config, temporaryDirectory, files }) => {
const Artifactor = __webpack_require__(29463);
const { Test } = __webpack_require__(26158);
// Set a new artifactor; don't rely on the one created by Environments.
// TODO: Make the test artifactor configurable.
config.artifactor = new Artifactor(temporaryDirectory);
const testConfig = config.with({
test_files: files,
contracts_build_directory: temporaryDirectory
});
return Test.run(testConfig, createInTestDebugFunction);
};
module.exports = {
prepareConfigAndRunTests
};
/***/ }),
/***/ 46394:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const parseCommandLineFlags = options => {
// parse out command line flags to merge in to the config
const grep = options.grep || options.g;
const bail = options.bail || options.b;
const reporter = options.reporter || options.r;
/**
* Reporter value passed on the command line has precedence over a reporter value in the config.
* If neither exist, then nothing is passed to mocha and it uses its default reporter type "spec".
* Note: It is important that reporter be completely omitted, and not be set to undefined!
* As setting it to undefined will ignore the reporter value specified in the config.
*/
return reporter === undefined
? { mocha: { grep, bail } }
: { mocha: { grep, bail, reporter } };
};
module.exports = async function (options) {
const Config = __webpack_require__(20553);
const { Environment, Develop } = __webpack_require__(76765);
const { copyArtifactsToTempDir } = __webpack_require__(93622);
const { determineTestFilesToRun } = __webpack_require__(13799);
const { prepareConfigAndRunTests } = __webpack_require__(55472);
const { configureManagedGanache } = __webpack_require__(84973);
const optionsToMerge = parseCommandLineFlags(options);
const config = Config.detect(options).merge(optionsToMerge);
// if "development" exists, default to using that for testing
if (!config.network && config.networks.development) {
config.network = "development";
}
if (!config.network) {
config.network = "test";
} else {
await Environment.detect(config);
}
// Start managed ganache network
async function startGanacheAndRunTests(
ipcOptions,
ganacheOptions,
truffleConfig
) {
const { disconnect } = await Develop.connectOrStart(
ipcOptions,
ganacheOptions,
truffleConfig?.solidityLog?.displayPrefix ?? ""
);
const ipcDisconnect = disconnect;
await Environment.develop(truffleConfig, ganacheOptions);
const { temporaryDirectory } = await copyArtifactsToTempDir(truffleConfig);
const numberOfFailures = await prepareConfigAndRunTests({
config: truffleConfig,
files,
temporaryDirectory
});
ipcDisconnect();
return numberOfFailures;
}
if (config.stacktraceExtra) {
config.stacktrace = true;
config.compileAllDebug = true;
}
// enables in-test debug() interrupt, or stacktraces, forcing compileAll
if (config.debug || config.stacktrace || config.compileAllDebug) {
config.compileAll = true;
}
const { file } = options;
const inputArgs = options._;
const files = determineTestFilesToRun({
config,
inputArgs,
inputFile: file
});
const configuredNetwork = config.networks[config.network];
const testNetworkDefinedAndUsed =
configuredNetwork && config.network === "test";
const noProviderHostOrUrlConfigured =
configuredNetwork &&
!configuredNetwork.provider &&
!configuredNetwork.host &&
!configuredNetwork.url;
let numberOfFailures;
if (
(testNetworkDefinedAndUsed && noProviderHostOrUrlConfigured) ||
!configuredNetwork
) {
const defaultPort = await __webpack_require__(15959)();
const defaultMnemonic =
"candy maple cake sugar pudding cream honey rich smooth crumble sweet treat";
// configuredNetwork will spread only when it is defined and ignored when undefined
const managedNetworkOptions = {
port: defaultPort,
...configuredNetwork
};
const mnemonic = managedNetworkOptions.mnemonic || defaultMnemonic;
const ganacheOptions = configureManagedGanache(
config,
managedNetworkOptions,
mnemonic
);
const ipcOptions = { network: "test" };
numberOfFailures = await startGanacheAndRunTests(
ipcOptions,
ganacheOptions,
config
);
} else {
// Use unmanaged network with user specified config if provider, host or url exists
await Environment.detect(config);
const { temporaryDirectory } = await copyArtifactsToTempDir(config);
numberOfFailures = await prepareConfigAndRunTests({
config,
files,
temporaryDirectory
});
}
return numberOfFailures;
};
/***/ }),
/***/ 84973:
/***/ ((module) => {
function resolveNetworkId(network_id) {
// Use default network_id if "*" is defined in config
if (network_id === "*") {
return Date.now();
}
const parsedNetworkId = parseInt(network_id, 10);
if (isNaN(parsedNetworkId)) {
const error =
`The network id specified in the truffle config ` +
`(${network_id}) is not valid. Please properly configure the network id as an integer value.`;
throw new Error(error);
}
return parsedNetworkId;
}
// This function returns the first defined argument value
const getFirstDefinedValue = (...values) =>
values.find(value => value !== undefined);
function configureManagedGanache(config, networkConfig, mnemonic) {
const host = getFirstDefinedValue(
networkConfig.host,
"127.0.0.1" // Use as default host
);
const port = getFirstDefinedValue(
networkConfig.port,
9545 // Use as default port
);
const network_id = getFirstDefinedValue(
networkConfig.network_id,
5777 // Use as default network_id
);
const resolvedNetworkId = resolveNetworkId(network_id);
const total_accounts = getFirstDefinedValue(
networkConfig.accounts,
networkConfig.total_accounts,
10 // Use as default number of accounts
);
const default_balance_ether = getFirstDefinedValue(
networkConfig.defaultEtherBalance,
networkConfig.default_balance_ether,
100 // Use as default ether balance for each account
);
const blockTime = getFirstDefinedValue(
networkConfig.blockTime,
0 // Use as default block time
);
const gasLimit = getFirstDefinedValue(
networkConfig.gasLimit,
0x6691b7 // Use as default gasLimit
);
const gasPrice = getFirstDefinedValue(
networkConfig.gasPrice,
0x77359400 // Use default gas price 2000000000 wei
);
const genesisTime = getFirstDefinedValue(
// Higher precedence is given to the networkConfig.time or networkConfig.genesis_time
networkConfig.time,
networkConfig.genesis_time,
config.time,
config.genesis_time
);
const fork = networkConfig.fork;
const hardfork = networkConfig.hardfork;
const ganacheOptions = {
host,
port,
network_id: resolvedNetworkId,
total_accounts,
default_balance_ether,
blockTime,
fork,
hardfork,
mnemonic,
gasLimit,
gasPrice,
time: genesisTime,
miner: {
instamine: "eager"
}
};
return ganacheOptions;
}
module.exports = { configureManagedGanache, getFirstDefinedValue };
/***/ }),
/***/ 12834:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const debugModule = __webpack_require__(15158);
const debug = debugModule("lib:debug:mocha");
const colors = __webpack_require__(83196);
const util = __webpack_require__(73837);
const { CLIDebugger } = __webpack_require__(458);
const execute = __webpack_require__(41441);
class CLIDebugHook {
constructor(config, compilations, runner) {
this.config = config;
this.compilations = compilations;
this.runner = runner; // mocha runner (**not** lib/test/testrunner)
}
async debug(operation) {
// turn off timeouts for the current runnable
// HACK we don't turn it back on because it doesn't work...
// tests that take a long time _after_ debug break just won't timeout
await this.disableTimeout();
const { txHash, result, method } = await this.invoke(operation);
debug("txHash: %o", txHash);
this.printStartTestHook(method);
const interpreter = await new CLIDebugger(this.config, {
compilations: this.compilations,
txHash
}).run();
await interpreter.start();
this.printStopTestHook();
return result;
}
async start() {}
async disableTimeout() {
(await this.runner).currentRunnable.timeout(0);
}
async invoke(operation) {
const method = await this.detectMethod(operation);
const { action } = method;
switch (action) {
case "deploy": {
const result = await operation;
return {
txHash: result.transactionHash, // different name; who knew
method,
result
};
}
case "send": {
const result = await operation;
return { txHash: result.tx, method, result };
}
case "call": {
// replays as send
const { contract, fn, abi, args, address } = method;
// get the result of the call
const result = await operation;
// and replay it as a transaction so we can debug
// bit of a HACK: properly making a call act like a tx requires forking
const { tx: txHash } = await execute.send.call(
contract,
fn,
abi,
address
)(...args);
return { txHash, method, result };
}
default: {
throw new Error(`Unsupported action for debugging: ${action}`);
}
}
}
detectMethod(promiEvent) {
return new Promise(accept => {
for (let action of ["send", "call", "deploy"]) {
promiEvent.on(
`execute:${action}:method`,
({ fn, abi, args, contract, address }) => {
accept({
fn,
abi,
args,
address,
contract,
action
});
}
);
}
});
}
printStartTestHook(method) {
const formatOperation = ({
action,
contract: { contractName },
abi,
args
}) => {
switch (action) {
case "deploy": {
return colors.bold(
`${contractName}.new(${args.map(util.inspect).join(", ")})`
);
}
case "call":
case "send": {
return colors.bold(
`${contractName}.${abi.name}(${args.map(util.inspect).join(", ")})`
);
}
}
};
this.config.logger.log("");
this.config.logger.log(" ...");
this.config.logger.log(
colors.cyan(
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
)
);
this.config.logger.log(" Test run interrupted.");
this.config.logger.log(` Debugging ${formatOperation(method)}`);
this.config.logger.log(
colors.cyan(
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
)
);
this.config.logger.log("");
}
printStopTestHook() {
this.config.logger.log("");
this.config.logger.log("");
this.config.logger.log(
colors.cyan(
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
)
);
this.config.logger.log(" Debugger stopped. Test resuming");
this.config.logger.log(
colors.cyan(
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
)
);
this.config.logger.log(" ...");
this.config.logger.log("");
}
}
module.exports = {
CLIDebugHook
};
/***/ }),
/***/ 64956:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.SolidityTest = void 0;
// @ts-ignore
const test_js_1 = __importDefault(__webpack_require__(50210));
// @ts-ignore
const suite_js_1 = __importDefault(__webpack_require__(83794));
const deployer_1 = __importDefault(__webpack_require__(669));
const compile_solidity_1 = __webpack_require__(4273);
const compile_common_1 = __webpack_require__(29833);
const debug_1 = __importDefault(__webpack_require__(15158));
const debug = (0, debug_1.default)("lib:testing:soliditytest");
exports.SolidityTest = {
define(abstraction, dependencyPaths, runner, mocha) {
return __awaiter(this, void 0, void 0, function* () {
const self = this;
const suite = new suite_js_1.default(abstraction.contract_name, {});
suite.timeout(runner.beforeTimeout);
// Set up our runner's needs first.
suite.beforeAll("prepare suite", function () {
return __awaiter(this, void 0, void 0, function* () {
// This compiles some native contracts (including the assertion library
// contracts) which need to be compiled before initializing the runner
yield self.compileNewAbstractInterface.bind(this)(runner);
yield runner.initialize.bind(runner)();
runner.disableChecksOnEventDecoding(); //for handling of test events on Solidity <0.7.6 due to empty string problem
yield self.deployTestDependencies.bind(this)(abstraction, dependencyPaths, runner);
});
});
suite.afterAll("clean up", function () {
runner.reEnableChecksOnEventDecoding();
});
suite.beforeEach("before test", function () {
return __awaiter(this, void 0, void 0, function* () {
yield runner.startTest(this);
});
});
// Function that checks transaction logs to see if a test failed.
function checkResultForFailure(result) {
return __awaiter(this, void 0, void 0, function* () {
const logs = result.receipt.rawLogs;
for (const log of logs) {
const decodings = yield runner.decoder.decodeLog(log, {
disableChecks: true
});
for (const decoding of decodings) {
//check: is this a TestEvent?
//note: we don't check the argument names
if (decoding.abi.name === "TestEvent" &&
decoding.arguments.length === 2 &&
decoding.arguments[0].value.type.typeClass === "bool" &&
decoding.arguments[0].indexed &&
decoding.arguments[1].value.type.typeClass === "string" &&
!decoding.arguments[1].indexed) {
//if so: did the test fail?
if (!decoding.arguments[0].value.value.asBoolean) {
//if so: extract the message
let messageDecoding = decoding.arguments[1].value;
let message;
switch (messageDecoding.value.kind) {
case "valid":
message = messageDecoding.value.asString;
break;
case "malformed":
//use buffer to convert hex to string
//(this causes malformed UTF-8 to become U+FFFD)
message = Buffer.from(messageDecoding.value.asHex.slice(2), "hex").toString();
}
throw new Error(message);
}
}
}
}
});
}
// Add functions from test file.
for (const item of abstraction.abi) {
if (item.type !== "function") {
continue;
}
const hookTypes = ["beforeAll", "beforeEach", "afterAll", "afterEach"];
for (const hookType of hookTypes) {
if (item.name.startsWith(hookType)) {
suite[hookType](item.name, () => __awaiter(this, void 0, void 0, function* () {
let deployed = yield abstraction.deployed();
yield checkResultForFailure(yield deployed[item.name]());
}));
}
}
if (item.name.startsWith("test")) {
const test = new test_js_1.default(item.name, () => __awaiter(this, void 0, void 0, function* () {
let deployed = yield abstraction.deployed();
yield checkResultForFailure(yield deployed[item.name]());
}));
test.timeout(runner.testTimeout);
suite.addTest(test);
}
}
suite.afterEach("after test", function () {
return __awaiter(this, void 0, void 0, function* () {
yield runner.endTest(this);
});
});
mocha.suite.addSuite(suite);
});
},
compileNewAbstractInterface(runner) {
return __awaiter(this, void 0, void 0, function* () {
debug("compiling");
const config = runner.config;
const truffleLibraries = [
"truffle/Assert.sol",
"truffle/AssertAddress.sol",
"truffle/AssertAddressArray.sol",
"truffle/AssertBalance.sol",
"truffle/AssertBool.sol",
"truffle/AssertBytes32.sol",
"truffle/AssertBytes32Array.sol",
"truffle/AssertGeneral.sol",
"truffle/AssertInt.sol",
"truffle/AssertIntArray.sol",
"truffle/AssertString.sol",
"truffle/AssertUint.sol",
"truffle/AssertUintArray.sol",
"truffle/DeployedAddresses.sol",
"truffle/SafeSend.sol",
"truffle/Console.sol"
];
const { compilations } = yield compile_solidity_1.Compile.sourcesWithDependencies({
paths: truffleLibraries,
options: runner.config.with({
quiet: true
})
});
const contracts = compilations.reduce((a, compilation) => {
return a.concat(compilation.contracts);
}, []);
// Set network values.
for (let contract of contracts) {
contract.network_id = config.network_id;
contract.default_network = config.default_network;
}
yield config.artifactor.saveAll(contracts.map(compile_common_1.Shims.NewToLegacy.forContract));
debug("compiled");
});
},
deployTestDependencies(abstraction, dependencyPaths, runner) {
return __awaiter(this, void 0, void 0, function* () {
debug("deploying %s", abstraction.contract_name);
const deployer = new deployer_1.default(runner.config.with({
logger: { log() { } }
}));
debug("starting deployer");
yield deployer.start();
const testLibraries = [
"Assert",
"AssertAddress",
"AssertAddressArray",
"AssertBalance",
"AssertBool",
"AssertBytes32",
"AssertBytes32Array",
"AssertGeneral",
"AssertInt",
"AssertIntArray",
"AssertString",
"AssertUint",
"AssertUintArray",
"DeployedAddresses",
"Console"
];
const testAbstractions = testLibraries.map(name => runner.config.resolver.require(`truffle/${name}.sol`));
const SafeSend = runner.config.resolver.require("SafeSend");
debug("deploying test libs");
for (const testLib of testAbstractions) {
yield deployer.deploy(testLib);
yield deployer.link(testLib, abstraction);
}
debug("linking dependencies");
for (const dependencyPath of dependencyPaths) {
const dependency = runner.config.resolver.require(dependencyPath);
if (dependency.isDeployed()) {
yield deployer.link(dependency, abstraction);
}
}
debug("deploying contract");
yield deployer.deploy(abstraction);
const deployed = yield abstraction.deployed();
let balance;
if (deployed.initialBalance) {
balance = yield deployed.initialBalance.call();
}
else {
balance = 0;
}
if (balance !== 0) {
yield deployer.deploy(SafeSend);
const safeSend = yield SafeSend.deployed();
yield safeSend.deliver(deployed.address, { value: balance });
}
debug("deployed %s", abstraction.contract_name);
});
}
};
//# sourceMappingURL=SolidityTest.js.map
/***/ }),
/***/ 83725:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Test = void 0;
const colors_1 = __importDefault(__webpack_require__(83196));
const chai_1 = __importDefault(__webpack_require__(14960));
const path = __webpack_require__(71017);
const interface_adapter_1 = __webpack_require__(36339);
const config_1 = __importDefault(__webpack_require__(20553));
const workflow_compile_1 = __importDefault(__webpack_require__(37017));
const resolver_1 = __webpack_require__(48511);
const TestRunner_1 = __webpack_require__(34036);
const SolidityTest_1 = __webpack_require__(64956);
const rangeUtils_1 = __importDefault(__webpack_require__(32739));
const expect = __importStar(__webpack_require__(14096));
const migrate_1 = __importDefault(__webpack_require__(22478));
const profiler_1 = __webpack_require__(22860);
const original_require_1 = __importDefault(__webpack_require__(44516));
const Codec = __importStar(__webpack_require__(20102));
const debug_1 = __importDefault(__webpack_require__(15158));
const debug = (0, debug_1.default)("lib:test");
const debugger_1 = __importDefault(__webpack_require__(92851));
let Mocha; // Late init with "mocha" or "mocha-parallel-tests"
chai_1.default.use((__webpack_require__(1465)["default"]));
exports.Test = {
run: function (options, createInTestDebugFunction) {
return __awaiter(this, void 0, void 0, function* () {
expect.options(options, [
"contracts_directory",
"contracts_build_directory",
"migrations_directory",
"test_files",
"network",
"network_id",
"provider"
]);
// if test is used standalone, this function won't be setup like in core
if (createInTestDebugFunction === undefined) {
createInTestDebugFunction = () => {
return () => {
config.logger.log(`${colors_1.default.bold("Warning:")} Use of in-test debugging is only available when running ` +
`truffle test --debug.`);
};
};
}
const config = config_1.default.default().merge(options);
config.test_files = config.test_files.map((testFile) => {
return path.resolve(testFile);
});
const interfaceAdapter = (0, interface_adapter_1.createInterfaceAdapter)({
provider: config.provider,
networkType: config.networks[config.network].type
});
// `accounts` will be populated before each contract() invocation
// and passed to it so tests don't have to call it themselves.
const web3 = new interface_adapter_1.Web3Shim({
provider: config.provider,
networkType: config.networks[config.network].type
? config.networks[config.network].type
: "web3js"
});
// Override console.warn() because web3 outputs gross errors to it.
// e.g., https://github.com/ethereum/web3.js/blob/master/lib/web3/allevents.js#L61
// Output looks like this during tests: https://gist.github.com/tcoulter/1988349d1ec65ce6b958
const warn = config.logger.warn;
config.logger.warn = function (message) {
if (message === "cannot find event for log") {
return;
}
else {
if (warn)
warn.apply(console, arguments);
}
};
const mocha = this.createMocha(config);
// set up a promise on this instance to resolve to
// Mocha's "runner" returned by `mocha.run(...)`.
//
// do this upfront so that the promise is available
// immediately, even though mocha.run happens at the very
// end of this setup.
let setMochaRunner;
this.mochaRunner = new Promise(resolve => {
setMochaRunner = resolve;
});
const jsTests = config.test_files.filter((file) => {
return path.extname(file) !== ".sol";
});
const solTests = config.test_files.filter((file) => {
return path.extname(file) === ".sol";
});
// Add Javascript tests because there's nothing we need to do with them.
// Solidity tests will be handled later.
jsTests.forEach((file) => {
// There's an idiosyncracy in Mocha where the same file can't be run twice
// unless we delete the `require` cache.
// https://github.com/mochajs/mocha/issues/995
delete original_require_1.default.cache[file];
mocha.addFile(file);
});
const accounts = yield this.getAccounts(interfaceAdapter);
const testResolver = new resolver_1.Resolver(config);
const { compilations } = yield this.compileContractsWithTestFilesIfNeeded(solTests, config, testResolver);
const testContracts = solTests.map((testFilePath) => {
return testResolver.require(testFilePath);
});
const runner = new TestRunner_1.TestRunner(config);
if (config.migrateNone || config["migrate-none"]) {
if (config.events) {
config.events.emit("test:migration:skipped");
}
}
else {
yield this.performInitialDeploy(config, testResolver);
}
const sourcePaths = []
.concat(...compilations.map((compilation) => compilation.sourceIndexes) //we don't need the indices here, just the paths
)
.filter(path => path); //make sure we don't pass in any undefined
yield this.defineSolidityTests(mocha, testContracts, sourcePaths, runner);
const debuggerCompilations = Codec.Compilations.Utils.shimCompilations(compilations);
//for stack traces, we'll need to set up a light-mode debugger...
let bugger;
if (config.stacktrace) {
debug("stacktraces on!");
bugger = yield debugger_1.default.forProject({
compilations: debuggerCompilations,
provider: config.provider,
lightMode: true
});
}
yield this.setJSTestGlobals({
config,
web3,
interfaceAdapter,
accounts,
testResolver,
runner,
compilations: debuggerCompilations,
bugger,
createInTestDebugFunction
});
// Finally, run mocha.
process.on("unhandledRejection", reason => {
throw reason;
});
return new Promise(resolve => {
const mochaRunner = mocha.run((failures) => {
config.logger.warn = warn;
resolve(failures);
});
// finish setting up the mocha runner so that the
// previously-made promise resolves.
setMochaRunner(mochaRunner);
});
});
},
createMocha: function (config) {
// Allow people to specify config.mocha in their config.
const mochaConfig = config.mocha || {};
// Propagate --bail option to mocha
mochaConfig.bail = config.bail;
// If the command line overrides color usage, use that.
if (config.color != null) {
mochaConfig.color = config.color;
}
else if (config.colors != null) {
// --colors is a mocha alias for --color
mochaConfig.color = config.colors;
}
// Default to true if configuration isn't set anywhere.
if (mochaConfig.color == null) {
mochaConfig.color = true;
}
Mocha = mochaConfig.package || __webpack_require__(3270);
delete mochaConfig.package;
const mocha = new Mocha(mochaConfig);
return mocha;
},
getAccounts: function (interfaceAdapter) {
return interfaceAdapter.getAccounts();
},
compileContractsWithTestFilesIfNeeded: function (solidityTestFiles, config, testResolver) {
return __awaiter(this, void 0, void 0, function* () {
const updated = (yield profiler_1.Profiler.updated(config.with({ resolver: testResolver }))) || [];
const compiler = config.compileNone || config["--compile-none"] ? "none" : config.compiler;
let compileConfig = config.with({
all: config.compileAll === true,
compiler,
files: updated.concat(solidityTestFiles),
resolver: testResolver,
quiet: config.runnerOutputOnly || config.quiet,
quietWrite: true
});
if (config.compileAllDebug) {
let versionString = ((compileConfig.compilers || {}).solc || {}).version;
versionString = rangeUtils_1.default.resolveToRange(versionString);
if (rangeUtils_1.default.rangeContainsAtLeast(versionString, "0.6.3")) {
compileConfig = compileConfig.merge({
compilers: {
solc: {
settings: {
debug: {
revertStrings: "debug"
}
}
}
}
});
}
else {
config.logger.log(`\n${colors_1.default.bold("Warning:")} Extra revert string info requires Solidity v0.6.3 or higher. For more\n information, see release notes <https://github.com/ethereum/solidity/releases/tag/v0.6.3>`);
}
}
// Compile project contracts and test contracts
const { contracts, compilations } = yield workflow_compile_1.default.compileAndSave(compileConfig);
return {
contracts,
compilations
};
});
},
performInitialDeploy: function (config, resolver) {
const migrateConfig = config.with({
reset: true,
resolver: resolver,
quiet: true
});
return migrate_1.default.run(migrateConfig);
},
defineSolidityTests: (mocha, contracts, dependencyPaths, runner) => __awaiter(void 0, void 0, void 0, function* () {
for (const contract of contracts) {
yield SolidityTest_1.SolidityTest.define(contract, dependencyPaths, runner, mocha);
debug("defined solidity tests for %s", contract.contractName);
}
}),
setJSTestGlobals: function ({ config, web3, interfaceAdapter, accounts, testResolver, runner, compilations, bugger, //for stacktracing
createInTestDebugFunction }) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
// @ts-ignore
global.interfaceAdapter = interfaceAdapter;
// @ts-ignore
global.web3 = web3;
const resolvedChai = (_b = (_a = config.chai) === null || _a === void 0 ? void 0 : _a.package) !== null && _b !== void 0 ? _b : chai_1.default;
// @ts-ignore
global.assert = resolvedChai.assert;
// @ts-ignore
global.expect = resolvedChai.expect;
// @ts-ignore
global.artifacts = {
require: (importPath) => {
let contract = testResolver.require(importPath);
//HACK: both of the following should go by means
//of the provisioner, but I'm not sure how to make
//that work at the moment
contract.reloadJson = function () {
const reloaded = testResolver.require(importPath);
this._json = reloaded._json;
};
if (bugger) {
contract.debugger = bugger;
}
return contract;
}
};
// @ts-ignore
global.config = config.normalize(config);
// @ts-ignore
global[config.debugGlobal] = createInTestDebugFunction({
compilations,
mochaRunner: this.mochaRunner,
config
});
const template = function (tests) {
this.timeout(runner.testTimeout);
// @ts-ignore
before("prepare suite", function () {
return __awaiter(this, void 0, void 0, function* () {
this.timeout(runner.beforeTimeout);
yield runner.initialize();
});
});
// @ts-ignore
beforeEach("before test", function () {
return __awaiter(this, void 0, void 0, function* () {
yield runner.startTest();
});
});
// @ts-ignore
afterEach("after test", function () {
return __awaiter(this, void 0, void 0, function* () {
yield runner.endTest(this);
});
});
tests(accounts);
};
// @ts-ignore
global.contract = function (name, tests) {
Mocha.describe("Contract: " + name, function () {
template.bind(this, tests)();
});
};
// @ts-ignore
global.contract.only = function (name, tests) {
Mocha.describe.only("Contract: " + name, function () {
template.bind(this, tests)();
});
};
// @ts-ignore
global.contract.skip = function (name, tests) {
Mocha.describe.skip("Contract: " + name, function () {
template.bind(this, tests)();
});
};
});
}
};
//# sourceMappingURL=Test.js.map
/***/ }),
/***/ 34036:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.TestRunner = void 0;
const interface_adapter_1 = __webpack_require__(36339);
const web3_utils_1 = __importDefault(__webpack_require__(18269));
const config_1 = __importDefault(__webpack_require__(20553));
const migrate_1 = __importDefault(__webpack_require__(22478));
const resolver_1 = __webpack_require__(48511);
const expect = __importStar(__webpack_require__(14096));
const util_1 = __importDefault(__webpack_require__(73837));
const fs_1 = __importDefault(__webpack_require__(57147));
const path_1 = __importDefault(__webpack_require__(71017));
const debug_1 = __importDefault(__webpack_require__(15158));
const debug = (0, debug_1.default)("lib:testing:testrunner");
const Decoder = __importStar(__webpack_require__(18852));
const Codec = __importStar(__webpack_require__(20102));
const os_1 = __importDefault(__webpack_require__(22037));
class TestRunner {
constructor(options) {
expect.options(options, [
"resolver",
"provider",
"contracts_build_directory"
]);
this.config = config_1.default.default().merge(options);
this.logger = options.logger || console;
this.provider = options.provider;
this.canSnapshot = false;
this.firstSnapshot = true;
this.initialSnapshot = null;
this.interfaceAdapter = (0, interface_adapter_1.createInterfaceAdapter)({
provider: options.provider,
networkType: options.networks[options.network].type
});
this.decoder = null;
// For each test
this.currentTestStartBlock = null;
this.beforeTimeout =
(options.mocha && options.mocha.before_timeout) || 120000;
this.testTimeout = (options.mocha && options.mocha.timeout) || 300000;
}
disableChecksOnEventDecoding() {
this.disableChecks = true; //used by Solidity testing due to empty string problem on Solidity <0.7.6
}
reEnableChecksOnEventDecoding() {
this.disableChecks = false;
}
initialize() {
return __awaiter(this, void 0, void 0, function* () {
debug("initializing");
this.config.resolver = new resolver_1.Resolver(this.config);
if (this.firstSnapshot) {
debug("taking first snapshot");
try {
const initialSnapshot = yield this.snapshot();
this.canSnapshot = true;
this.initialSnapshot = initialSnapshot;
}
catch (error) {
debug("first snapshot failed");
debug("Error: %O", error);
}
this.firstSnapshot = false;
}
else {
yield this.resetState();
}
//set up decoder
let files = fs_1.default
.readdirSync(this.config.contracts_build_directory)
.filter(file => path_1.default.extname(file) === ".json");
let data = files.map(file => fs_1.default.readFileSync(path_1.default.join(this.config.contracts_build_directory, file), "utf8"));
let artifacts = data.map(text => JSON.parse(text));
this.decoder = yield Decoder.forProject({
provider: this.provider,
projectInfo: { artifacts }
});
});
}
deploy() {
return __awaiter(this, void 0, void 0, function* () {
yield migrate_1.default.run(this.config.with({
reset: true,
quiet: true
}));
});
}
resetState() {
return __awaiter(this, void 0, void 0, function* () {
if (this.canSnapshot) {
debug("reverting...");
yield this.revert(this.initialSnapshot);
this.initialSnapshot = yield this.snapshot();
}
else {
debug("redeploying...");
yield this.deploy();
}
});
}
startTest() {
return __awaiter(this, void 0, void 0, function* () {
const blockNumber = web3_utils_1.default.toBN(yield this.interfaceAdapter.getBlockNumber());
const one = web3_utils_1.default.toBN(1);
// Add one in base 10
this.currentTestStartBlock = blockNumber.add(one);
});
}
endTest(mocha) {
return __awaiter(this, void 0, void 0, function* () {
// Skip logging if test passes and `show-events` option is not true
if (mocha.currentTest.state !== "failed" && !this.config["show-events"]) {
return;
}
function indent(input, indentation, initialPrefix = "") {
const unindented = input.split(/\r?\n/);
return unindented
.map((line, index) => index === 0
? initialPrefix +
" ".repeat(indentation - initialPrefix.length) +
line
: " ".repeat(indentation) + line)
.join(os_1.default.EOL);
}
function printEvent(decoding, indentation = 0, initialPrefix = "") {
debug("raw event: %O", decoding);
const inspected = util_1.default.inspect(new Codec.Export.LogDecodingInspector(decoding), {
depth: null,
colors: true,
maxArrayLength: null,
breakLength: 80 - indentation //should this include prefix lengths as well?
});
return indent(inspected, indentation, initialPrefix);
}
if (this.decoder === null) {
throw new Error("Decoder has not yet been initialized.");
}
if (this.currentTestStartBlock === null) {
throw new Error("`currentTestStartBlock` has not been initialized. You must " +
"call `startTest` before calling `endTest`.");
}
const logs = yield this.decoder.events({
//NOTE: block numbers shouldn't be over 2^53 so this
//should be fine, but should change this once decoder
//accepts more general types