Categories

  • articles

Tags

  • solidity
  • cypto

When creating test cases to test your solidity code you will need to test conditions that causes throws. This will show you how to write those tests in javascript.

Make use of the OpenZeppelin expectThrow script

export default async promise => {
  try {
    await promise;
  } catch (error) {
    // TODO: Check jump destination to destinguish between a throw
    //       and an actual invalid jump.
    const invalidOpcode = error.message.search('invalid opcode') >= 0;
    // TODO: When we contract A calls contract B, and B throws, instead
    //       of an 'invalid jump', we get an 'out of gas' error. How do
    //       we distinguish this from an actual out of gas event? (The
    //       ganache log actually show an 'invalid jump' event.)
    const outOfGas = error.message.search('out of gas') >= 0;
    const revert = error.message.search('revert') >= 0;
    assert(
      invalidOpcode || outOfGas || revert,
      'Expected throw, got \'' + error + '\' instead',
    );
    return;
  }
  assert.fail('Expected throw not received');
};

In my test I have added that code to file in my test folder /helpers/expectThrow.js and have used as follow. Here the function getPeriodStartTimestamp is expected to throw when the value is 50000 or larger.

// Import the helper script
import expectThrow from './helpers/expectThrow';

const PeriodUtilWeek = artifacts.require("./PeriodUtilWeek.sol");

const BigNumber = web3.BigNumber;

contract('PeriodUtilWeek',function(accounts) {

  // Other tests

  describe('Test getPeriodStartTimestamp (Week)', async function() {

    beforeEach(async function () {
      this.periodUtilWeek = await PeriodUtilWeek.new();
    });

    it('Test exception', async function() {
      // Magic bit here!
      await expectThrow(this.periodUtilWeek.getPeriodStartTimestamp(new BigNumber('50000')));
    });
  });

  // Loads more tests
}

Fun Issue

Unexpected token import! This is because we need some Babel

/home/mmmmmm/dev/Project/solidityWork/profit/test/period_util_week.js:1
(function (exports, require, module, __filename, __dirname) { import expectThrow from './helpers/expectThrow';
                                                              ^^^^^^
SyntaxError: Unexpected token import
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:616:28)
    at loader (/home/mmmmmm/dev/Project/solidityWork/profit/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/home/mmmmmm/dev/Project/solidityWork/profit/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at /home/mmmmmm/.node_modules_global/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:231:27
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/home/mmmmmm/.node_modules_global/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:228:14)
    at Mocha.run (/home/mmmmmm/.node_modules_global/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:536:10)
    at /home/mmmmmm/.node_modules_global/lib/node_modules/truffle/build/webpack:/~/truffle-core/lib/test.js:125:1
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

To fix this add the following dependencies by editing package.json and adding under “devDependencies” the following

"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-2": "^6.18.0",
"babel-preset-stage-3": "^6.17.0",

Running npm install in the project directory to install the new packages

npm install

Create a new file in the project directory call .babelrc and put the following in there

{
  "presets": ["es2015", "stage-2", "stage-3"]
}

Now when you run the truffle test all should work again without a error

Update (2018-06-11)

Code coverage will stop working with same issue SyntaxError: Unexpected token import. To fix this add a network coverage to the truffle.js, see below example:

require('babel-register');
require('babel-polyfill');

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  networks: {
    mainnet: {
      host: 'localhost',
      port: 8545,
      network_id: '1', // Match any network id
      gas: 3500000,
      gasPrice: 10000000000
    },
    development: {
      host: "localhost",
      port: 7545,
      network_id: "*", // Match any network id
      gas: 4500000,
    },
    coverage: {
      host: "localhost",
      port: 7545,
      network_id: "*", // Match any network id
      gas: 4500000,
    },
    ropsten : {
      host: "127.0.0.1",
      port: 8545,
      network_id: "3", // Match any network id
      gas: 4500000,
    }
  },
  dependencies: {},
  solc: {
    optimizer: {
      enabled: true,
      runs: 200,
    },
  },
};