Add mocha options to solcoverjs (#401)

* Add mocha options in solcoverjs (for skipping tests)

* Plugin tests cleanup
truffle-plugin
cgewecke 5 years ago
parent 35e663170c
commit 503c300993
  1. 11
      dist/truffle.plugin.js
  2. 6
      test/integration/projects/multiple-migrations/.solcover.js
  3. 4
      test/integration/projects/multiple-migrations/test/contracta.js
  4. 2
      test/integration/projects/multiple-migrations/test/contractb.js
  5. 16
      test/units/truffle/errors.js
  6. 60
      test/units/truffle/flags.js
  7. 36
      test/units/truffle/standard.js
  8. 7
      test/util/integration.truffle.js
  9. 10
      test/util/verifiers.js

@ -22,6 +22,7 @@ async function plugin(truffleConfig){
let app; let app;
let error; let error;
let truffle; let truffle;
let solcoverjs;
let testsErrored = false; let testsErrored = false;
// This needs it's own try block because this logic // This needs it's own try block because this logic
@ -221,6 +222,16 @@ function loadSolcoverJS(ui, truffleConfig){
coverageConfig.cwd = truffleConfig.working_directory; coverageConfig.cwd = truffleConfig.working_directory;
coverageConfig.originalContractsDir = truffleConfig.contracts_directory; coverageConfig.originalContractsDir = truffleConfig.contracts_directory;
//Merge solcoverjs mocha opts into truffle's
truffleConfig.mocha = truffleConfig.mocha || {};
if (coverageConfig.mocha && typeof coverageConfig.mocha === 'object'){
truffleConfig.mocha = Object.assign(
truffleConfig.mocha,
coverageConfig.mocha
);
}
return coverageConfig; return coverageConfig;
} }

@ -1,4 +1,4 @@
module.exports = { module.exports = {
silent: process.env.SILENT ? true : false, "silent": false,
istanbulReporter: ['json-summary', 'text'] "istanbulReporter": [ "json-summary", "text"]
}; }

@ -5,11 +5,11 @@ contract("contracta", function(accounts) {
before(async () => instance = await ContractA.deployed()) before(async () => instance = await ContractA.deployed())
it('sends', async function(){ it('sends [ @skipForCoverage ]', async function(){
await instance.sendFn(); await instance.sendFn();
}); });
it('calls', async function(){ it('calls [ @skipForCoverage ]', async function(){
await instance.callFn(); await instance.callFn();
}) })
}); });

@ -1,6 +1,6 @@
const ContractB = artifacts.require("ContractB"); const ContractB = artifacts.require("ContractB");
contract("contractB", function(accounts) { contract("contractB [ @skipForCoverage ]", function(accounts) {
let instance; let instance;
before(async () => instance = await ContractB.deployed()) before(async () => instance = await ContractB.deployed())

@ -7,6 +7,10 @@ const verify = require('../../util/verifiers')
const mock = require('../../util/integration.truffle'); const mock = require('../../util/integration.truffle');
const plugin = require('../../../dist/truffle.plugin'); const plugin = require('../../../dist/truffle.plugin');
// =======
// Errors
// =======
describe('Truffle Plugin: error cases', function() { describe('Truffle Plugin: error cases', function() {
let truffleConfig; let truffleConfig;
let solcoverConfig; let solcoverConfig;
@ -31,12 +35,12 @@ describe('Truffle Plugin: error cases', function() {
} catch(err){ } catch(err){
assert( assert(
err.message.includes('Cannot locate expected contract sources folder'), err.message.includes('Cannot locate expected contract sources folder'),
`Should error when contract sources cannot be found: (output --> ${err.message}` `Should error when contract sources cannot be found:: ${err.message}`
); );
assert( assert(
err.message.includes('sc_temp/contracts'), err.message.includes('sc_temp/contracts'),
`Error message should contain path: (output --> ${err.message}` `Error message should contain path:: ${err.message}`
); );
} }
@ -53,7 +57,7 @@ describe('Truffle Plugin: error cases', function() {
} catch(err){ } catch(err){
assert( assert(
err.message.includes('Could not load .solcover.js config file.'), err.message.includes('Could not load .solcover.js config file.'),
`Should notify when solcoverjs has syntax error: (output --> ${err.message}` `Should notify when solcoverjs has syntax error:: ${err.message}`
); );
} }
@ -72,8 +76,8 @@ describe('Truffle Plugin: error cases', function() {
assert.fail() assert.fail()
} catch (err) { } catch (err) {
assert( assert(
err.message.includes('Unable to load plugin copy of Truffle library module'), err.message.includes('Unable to load plugin copy'),
`Should error on failed lib module load (output --> ${err.message}` `Should error on failed lib module load: ${err.message}`
); );
} }
}); });
@ -140,7 +144,7 @@ describe('Truffle Plugin: error cases', function() {
} catch(err){ } catch(err){
assert( assert(
err.toString().includes('/Unparseable.sol.'), err.toString().includes('/Unparseable.sol.'),
`Should throw instrumentation errors with file name (output --> ${err.toString()}` `Should throw instrumentation errors with file name: ${err.toString()}`
); );
assert(err.stack !== undefined, 'Should have error trace') assert(err.stack !== undefined, 'Should have error trace')

@ -8,7 +8,7 @@ const mock = require('../../util/integration.truffle');
const plugin = require('../../../dist/truffle.plugin'); const plugin = require('../../../dist/truffle.plugin');
// ======================= // =======================
// Standard Use-case Tests // CLI Options / Flags
// ======================= // =======================
describe('Truffle Plugin: command line options', function() { describe('Truffle Plugin: command line options', function() {
@ -28,8 +28,11 @@ describe('Truffle Plugin: command line options', function() {
it('truffle run coverage --file test/<fileName>', async function() { it('truffle run coverage --file test/<fileName>', async function() {
verify.cleanInitialState(); verify.cleanInitialState();
const testPath = path.join(truffleConfig.working_directory, 'test/specific_a.js'); truffleConfig.file = path.join(
truffleConfig.file = testPath; truffleConfig.working_directory,
'test/specific_a.js'
);
mock.installFullProject('test-files'); mock.installFullProject('test-files');
await plugin(truffleConfig); await plugin(truffleConfig);
@ -54,8 +57,11 @@ describe('Truffle Plugin: command line options', function() {
it('truffle run coverage --file test/<glob*>', async function() { it('truffle run coverage --file test/<glob*>', async function() {
verify.cleanInitialState(); verify.cleanInitialState();
const testPath = path.join(truffleConfig.working_directory, 'test/globby*'); truffleConfig.file = path.join(
truffleConfig.file = testPath; truffleConfig.working_directory,
'test/globby*'
);
mock.installFullProject('test-files'); mock.installFullProject('test-files');
await plugin(truffleConfig); await plugin(truffleConfig);
@ -80,8 +86,11 @@ describe('Truffle Plugin: command line options', function() {
it('truffle run coverage --file test/gl{o,b}*.js', async function() { it('truffle run coverage --file test/gl{o,b}*.js', async function() {
verify.cleanInitialState(); verify.cleanInitialState();
const testPath = path.join(truffleConfig.working_directory, 'test/gl{o,b}*.js'); truffleConfig.file = path.join(
truffleConfig.file = testPath; truffleConfig.working_directory,
'test/gl{o,b}*.js'
);
mock.installFullProject('test-files'); mock.installFullProject('test-files');
await plugin(truffleConfig); await plugin(truffleConfig);
@ -110,17 +119,20 @@ describe('Truffle Plugin: command line options', function() {
silent: process.env.SILENT ? true : false, silent: process.env.SILENT ? true : false,
istanbulReporter: ['json-summary', 'text'] istanbulReporter: ['json-summary', 'text']
}; };
fs.writeFileSync('.solcover.js', `module.exports=${JSON.stringify(solcoverConfig)}`);
// This relative path has to be ./ prefixed // Write solcoverjs to parent dir of sc_temp (where the test project is installed)
// (because it's path.joined to truffle's working_directory) fs.writeFileSync(
'.solcover.js',
`module.exports=${JSON.stringify(solcoverConfig)}`
);
// This relative path has to be ./ prefixed (it's path.joined to truffle's working_directory)
truffleConfig.solcoverjs = './../.solcover.js'; truffleConfig.solcoverjs = './../.solcover.js';
mock.install('Simple', 'simple.js'); mock.install('Simple', 'simple.js');
await plugin(truffleConfig); await plugin(truffleConfig);
// The relative solcoverjs uses the json-summary reporter which // The relative solcoverjs uses the json-summary reporter
// this assertion requires
const expected = [{ const expected = [{
file: mock.pathToContract(truffleConfig, 'Simple.sol'), file: mock.pathToContract(truffleConfig, 'Simple.sol'),
pct: 100 pct: 100
@ -132,68 +144,72 @@ describe('Truffle Plugin: command line options', function() {
it('truffle run coverage --help', async function(){ it('truffle run coverage --help', async function(){
verify.cleanInitialState(); verify.cleanInitialState();
truffleConfig.help = "true";
truffleConfig.help = "true";
truffleConfig.logger = mock.testLogger; truffleConfig.logger = mock.testLogger;
mock.install('Simple', 'simple.js', solcoverConfig); mock.install('Simple', 'simple.js', solcoverConfig);
await plugin(truffleConfig); await plugin(truffleConfig);
assert( assert(
mock.loggerOutput.val.includes('Usage'), mock.loggerOutput.val.includes('Usage'),
`Should output help with Usage instruction (output --> ${mock.loggerOutput.val}` `Should output help with Usage instruction : ${mock.loggerOutput.val}`
); );
}) })
it('truffle run coverage --version', async function(){ it('truffle run coverage --version', async function(){
verify.cleanInitialState(); verify.cleanInitialState();
truffleConfig.version = "true";
truffleConfig.version = "true";
truffleConfig.logger = mock.testLogger; truffleConfig.logger = mock.testLogger;
mock.install('Simple', 'simple.js', solcoverConfig); mock.install('Simple', 'simple.js', solcoverConfig);
await plugin(truffleConfig); await plugin(truffleConfig);
assert( assert(
mock.loggerOutput.val.includes('truffle'), mock.loggerOutput.val.includes('truffle'),
`Should output truffle version (output --> ${mock.loggerOutput.val}` `Should output truffle version: ${mock.loggerOutput.val}`
); );
assert( assert(
mock.loggerOutput.val.includes('ganache-core'), mock.loggerOutput.val.includes('ganache-core'),
`Should output ganache-core version (output --> ${mock.loggerOutput.val}` `Should output ganache-core version: ${mock.loggerOutput.val}`
); );
assert( assert(
mock.loggerOutput.val.includes('solidity-coverage'), mock.loggerOutput.val.includes('solidity-coverage'),
`Should output solidity-coverage version (output --> ${mock.loggerOutput.val}` `Should output solidity-coverage version: ${mock.loggerOutput.val}`
); );
}) })
it('truffle run coverage --useGlobalTruffle', async function(){ it('truffle run coverage --useGlobalTruffle', async function(){
verify.cleanInitialState(); verify.cleanInitialState();
truffleConfig.useGlobalTruffle = true;
truffleConfig.useGlobalTruffle = true;
truffleConfig.logger = mock.testLogger; truffleConfig.logger = mock.testLogger;
mock.install('Simple', 'simple.js', solcoverConfig); mock.install('Simple', 'simple.js', solcoverConfig);
await plugin(truffleConfig); await plugin(truffleConfig);
assert( assert(
mock.loggerOutput.val.includes('global node_modules'), mock.loggerOutput.val.includes('global node_modules'),
`Should notify it's using global truffle (output --> ${mock.loggerOutput.val}` `Should notify it's using global truffle: ${mock.loggerOutput.val}`
); );
}); });
it('truffle run coverage --usePluginTruffle', async function(){ it('truffle run coverage --usePluginTruffle', async function(){
verify.cleanInitialState(); verify.cleanInitialState();
truffleConfig.usePluginTruffle = true;
truffleConfig.usePluginTruffle = true;
truffleConfig.logger = mock.testLogger; truffleConfig.logger = mock.testLogger;
mock.install('Simple', 'simple.js', solcoverConfig); mock.install('Simple', 'simple.js', solcoverConfig);
await plugin(truffleConfig); await plugin(truffleConfig);
assert( assert(
mock.loggerOutput.val.includes('fallback Truffle library module'), mock.loggerOutput.val.includes('fallback Truffle library module'),
`Should notify it's using plugin truffle lib copy (output --> ${mock.loggerOutput.val}` `Should notify it's using plugin truffle lib copy: ${mock.loggerOutput.val}`
); );
}); });
}); });

@ -82,6 +82,40 @@ describe('Truffle Plugin: standard use cases', function() {
verify.lineCoverage(expected); verify.lineCoverage(expected);
}); });
// This project has [ @skipForCoverage ] tags in the test descriptions
// at selected 'contract' and 'it' blocks.
it('uses solcoverjs mocha options', async function() {
verify.cleanInitialState();
solcoverConfig.mocha = {
grep: '@skipForCoverage',
invert: true,
};
solcoverConfig.silent = process.env.SILENT ? true : false,
solcoverConfig.istanbulReporter = ['json-summary', 'text']
mock.installFullProject('multiple-migrations', solcoverConfig);
await plugin(truffleConfig);
const expected = [
{
file: mock.pathToContract(truffleConfig, 'ContractA.sol'),
pct: 0
},
{
file: mock.pathToContract(truffleConfig, 'ContractB.sol'),
pct: 0,
},
{
file: mock.pathToContract(truffleConfig, 'ContractC.sol'),
pct: 100,
},
];
verify.lineCoverage(expected);
});
it('project skips a folder', async function() { it('project skips a folder', async function() {
verify.cleanInitialState(); verify.cleanInitialState();
mock.installFullProject('skipping'); mock.installFullProject('skipping');
@ -116,7 +150,7 @@ describe('Truffle Plugin: standard use cases', function() {
assert( assert(
mock.loggerOutput.val.includes('native solidity tests'), mock.loggerOutput.val.includes('native solidity tests'),
`Should warn it is skipping native solidity tests (output --> ${mock.loggerOutput.val}` `Should warn it is skipping native solidity tests: ${mock.loggerOutput.val}`
); );
}); });

@ -187,10 +187,15 @@ function installDouble(contracts, test, config) {
decacheConfigs(); decacheConfigs();
}; };
function installFullProject(name) { function installFullProject(name, config) {
shell.mkdir(temp); shell.mkdir(temp);
shell.cp('-Rf', `${projectPath}${name}/{.,}*`, temp); shell.cp('-Rf', `${projectPath}${name}/{.,}*`, temp);
if (config){
const configjs = getSolcoverJS(config);
fs.writeFileSync(`${temp}/.solcover.js`, configjs);
}
decacheConfigs(); decacheConfigs();
} }

@ -7,7 +7,15 @@ function pathExists(path) { return shell.test('-e', path); }
function lineCoverage(expected=[]){ function lineCoverage(expected=[]){
let summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json')); let summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json'));
expected.forEach(item => assert(summary[item.file].lines.pct === item.pct))
expected.forEach((item, idx) => {
assert(
summary[item.file].lines.pct === item.pct,
`For condition ${idx} - expected ${item.pct} %,` +
`saw - ${summary[item.file].lines.pct} %`
)
});
} }
function coverageMissing(expected=[]){ function coverageMissing(expected=[]){

Loading…
Cancel
Save