From cd5b32666dfa2eedb97ca7faf827d87f42e8cc44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 10 May 2019 21:09:10 -0300 Subject: [PATCH 01/13] Rename shouldFail to expectFailure. --- CHANGELOG.md | 3 +- README.md | 22 +++---- src/{shouldFail.js => expectFailure.js} | 34 ++++------- .../ganache-core-2.1.x/test/Tested.test.js | 6 +- .../test/Tested.test.js | 6 +- test/src/expectEvent.test.js | 28 ++++----- ...ouldFail.test.js => expectFailure.test.js} | 60 +++++++++---------- test/src/send.test.js | 10 ++-- test/src/time.test.js | 6 +- 9 files changed, 82 insertions(+), 93 deletions(-) rename src/{shouldFail.js => expectFailure.js} (66%) rename test/src/{shouldFail.test.js => expectFailure.test.js} (55%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d44aa7c..b55fb75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ * `shouldFail.reverting.withMessage` fails if no error string is provided. ([#28](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/28) * Rename `makeInterfaceId` to `makeInterfaceId.ERC165`, and add `makeInterfaceId.ERC1820`. ([#21](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/21) * Add possibility to configure a custom web3 instance. ([#38](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/38)) - + * Rename `shouldFail` to `expectFailure`. ([#39](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/39)) + #### How to upgrade from 0.3 - Change all occurences of `makeInterfaceId` to `makeInterfaceId.ERC165`. - Some uses of `shouldFail.reverting.withMessage` may fail now. This means it was being used incorrectly and an error string to match against should be added. Alternatively, if the error message is unknown, use `shouldFail.reverting` instead. diff --git a/README.md b/README.md index aa236ef..bb2da6b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ npm install --save-dev openzeppelin-test-helpers ```javascript // Import all required modules from openzeppelin-test-helpers -const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); +const { BN, constants, expectEvent, expectFailure } = require('openzeppelin-test-helpers'); // Import preferred chai flavor: both expect and should are supported const { expect } = require('chai'); @@ -30,7 +30,7 @@ contract('ERC20', ([sender, receiver]) => { it('reverts when transferring tokens to the zero address', async function () { // Edge cases that trigger a require statement can be tested for, optionally checking the revert reason as well - await shouldFail.reverting(this.erc20.transfer(constants.ZERO_ADDRESS, this.value, { from: sender })); + await expectFailure.revert(this.erc20.transfer(constants.ZERO_ADDRESS, this.value, { from: sender })); }); it('emits a Transfer event on successful transfers', async function () { @@ -177,14 +177,14 @@ A chai [should](https://www.chaijs.com/api/bdd/) instance, containing the `bignu --- -### shouldFail -Collection of assertions for failures (similar to [chai's `throw`](https://www.chaijs.com/api/bdd/#method_throw)). `shouldFail` will accept any exception type, but more specific functions exist and their usage is encouraged. +### expectFailure +Collection of assertions for failures (similar to [chai's `throw`](https://www.chaijs.com/api/bdd/#method_throw)). `expectFailure` will accept any exception type, but more specific functions exist and their usage is encouraged. -#### async shouldFail.reverting (promise) +#### async expectFailure.revert (promise) Only accepts failures caused due to an EVM revert (e.g. a failed `require`). -#### async shouldFail.reverting.withMessage (promise, message) -Like `shouldFail.reverting`, this helper only accepts failures caused due to an EVM revert (e.g. a failed `require`). Furthermore, it checks whether revert reason string includes passed `message`. For example: +#### async expectFailure.revert.withMessage (promise, message) +Like `expectFailure.revert`, this helper only accepts failures caused due to an EVM revert (e.g. a failed `require`). Furthermore, it checks whether revert reason string includes passed `message`. For example: ```solidity contract Owned { @@ -203,7 +203,7 @@ contract Owned { Can be tested as follows: ```javascript -const { shouldFail } = require('openzeppelin-test-helpers'); +const { expectFailure } = require('openzeppelin-test-helpers'); const Owned = artifacts.require('Owned'); @@ -214,7 +214,7 @@ contract('Owned', ([owner, other]) => { describe('doOwnerOperation', function() { it('Fails when called by a non-owner account', async function () { - await shouldFail.reverting.withMessage(this.owned.doOwnerOperation({ from: other }), "Unauthorized"); + await expectFailure.revert.withMessage(this.owned.doOwnerOperation({ from: other }), "Unauthorized"); }); }); ... @@ -222,10 +222,10 @@ contract('Owned', ([owner, other]) => { Use this helper to specify the expected error message, when you're testing a function that can revert for multiple reasons. -#### async shouldFail.throwing (promise) +#### async expectFailure.throw (promise) Only accepts failures due to a failed `assert` (which executes an invalid opcode). -#### async shouldFail.outOfGas (promise) +#### async expectFailure.outOfGas (promise) Only accepts failures due to the transaction running out of gas. --- diff --git a/src/shouldFail.js b/src/expectFailure.js similarity index 66% rename from src/shouldFail.js rename to src/expectFailure.js index 467e8b4..64ac23c 100644 --- a/src/shouldFail.js +++ b/src/expectFailure.js @@ -4,7 +4,7 @@ const { expect } = require('chai'); const colors = require('ansi-colors'); const semver = require('semver'); -async function shouldFailWithMessage (promise, message) { +async function expectFailureWithMessage (promise, message) { try { await promise; } catch (error) { @@ -19,19 +19,7 @@ async function shouldFailWithMessage (promise, message) { expect.fail('Expected failure not received'); } -async function reverting (promise) { - await shouldFailWithMessage(promise, 'revert'); -} - -async function throwing (promise) { - await shouldFailWithMessage(promise, 'invalid opcode'); -} - -async function outOfGas (promise) { - await shouldFailWithMessage(promise, 'out of gas'); -} - -async function shouldFail (promise) { +async function expectFailure (promise) { try { await promise; } catch (error) { @@ -47,25 +35,25 @@ async function withMessage (promise, message) { const matches = /TestRPC\/v([0-9.]+)\/ethereum-js/.exec(nodeInfo); const warn = function (msg) { console.log(`${colors.white.bgBlack('openzeppelin-test-helpers')} ${colors.black.bgYellow('WARN')} \ -shouldFail.reverting.withMessage: ` + msg); +expectFailure.revert.withMessage: ` + msg); }; if (matches === null || !(1 in matches)) { // warn users and skip reason check. warn('revert reason checking only supported on Ganache>=2.2.0'); - return shouldFail(promise); + return expectFailure(promise); } else if (!semver.satisfies(matches[1], '>=2.2.0')) { // warn users and skip reason check. warn(`current version of Ganache (${matches[1]}) doesn't return revert reason.`); - return shouldFail(promise); + return expectFailure(promise); } else { // actually perform revert reason check. - return shouldFailWithMessage(promise, message); + return expectFailureWithMessage(promise, message); } } -shouldFail.reverting = reverting; -shouldFail.reverting.withMessage = withMessage; -shouldFail.throwing = throwing; -shouldFail.outOfGas = outOfGas; +expectFailure.revert = (promise) => expectFailureWithMessage(promise, 'revert'); +expectFailure.revert.withMessage = withMessage; +expectFailure.throw = (promise) => expectFailureWithMessage(promise, 'invalid opcode'); +expectFailure.outOfGas = (promise) => expectFailureWithMessage(promise, 'out of gas'); -module.exports = shouldFail; +module.exports = expectFailure; diff --git a/test-integration/ganache-core-2.1.x/test/Tested.test.js b/test-integration/ganache-core-2.1.x/test/Tested.test.js index f245f88..c630f85 100644 --- a/test-integration/ganache-core-2.1.x/test/Tested.test.js +++ b/test-integration/ganache-core-2.1.x/test/Tested.test.js @@ -1,10 +1,10 @@ -const { shouldFail } = require('openzeppelin-test-helpers'); +const { expectFailure } = require('openzeppelin-test-helpers'); const { expect } = require('chai'); const Tested = artifacts.require('Tested'); contract('Tested', function (accounts) { - context('shouldFail.reverting.withMessage', async function () { + context('expectFailure.revert.withMessage', async function () { beforeEach(async function () { this.contract = await Tested.new(); }) @@ -25,7 +25,7 @@ contract('Tested', function (accounts) { } // With that said, following revert should be accepted without regard to the specified // reason message. - await shouldFail.reverting.withMessage(this.contract.failWithRevertReason(), expectedMessage); + await expectFailure.revert.withMessage(this.contract.failWithRevertReason(), expectedMessage); }) }) }) diff --git a/test-integration/simple-project-truffle-5.x/test/Tested.test.js b/test-integration/simple-project-truffle-5.x/test/Tested.test.js index b81aae5..72cf879 100644 --- a/test-integration/simple-project-truffle-5.x/test/Tested.test.js +++ b/test-integration/simple-project-truffle-5.x/test/Tested.test.js @@ -1,4 +1,4 @@ -const { BN, constants, expectEvent, shouldFail } = require('openzeppelin-test-helpers'); +const { BN, constants, expectEvent, expectFailure } = require('openzeppelin-test-helpers'); const Tested = artifacts.require('Tested'); @@ -13,7 +13,7 @@ contract('Tested', function (accounts) { }) it('detect reverts', async function () { - await shouldFail.reverting(this.contract.reverts()); + await expectFailure.revert(this.contract.reverts()); }); it('accepts calls with non-zero address', async function () { @@ -22,7 +22,7 @@ contract('Tested', function (accounts) { }); it('reverts with calls with non-zero address', async function () { - await shouldFail.reverting(this.contract.nonZeroAddress(constants.ZERO_ADDRESS)); + await expectFailure.revert(this.contract.nonZeroAddress(constants.ZERO_ADDRESS)); }); }); }); diff --git a/test/src/expectEvent.test.js b/test/src/expectEvent.test.js index aa67cf6..f1a3ea7 100644 --- a/test/src/expectEvent.test.js +++ b/test/src/expectEvent.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); const expectEvent = require('../../src/expectEvent'); -const shouldFail = require('../../src/shouldFail'); +const expectFailure = require('../../src/expectFailure'); const EventEmitter = artifacts.require('EventEmitter'); const IndirectEventEmitter = artifacts.require('IndirectEventEmitter'); @@ -30,13 +30,13 @@ describe('expectEvent', function () { }); it('throws if a correct JavaScript number is passed', async function () { - await shouldFail( + await expectFailure( expectEvent.inConstruction(this.emitter, 'ShortUint', { value: this.constructionValues.uint }) ); }); it('throws if an incorrect value is passed', async function () { - await shouldFail(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 })); + await expectFailure(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 })); }); }); @@ -46,7 +46,7 @@ describe('expectEvent', function () { }); it('throws if an incorrect value is passed', async function () { - await shouldFail(expectEvent.inConstruction(this.emitter, 'Boolean', + await expectFailure(expectEvent.inConstruction(this.emitter, 'Boolean', { value: !this.constructionValues.boolean } )); }); @@ -58,12 +58,12 @@ describe('expectEvent', function () { }); it('throws if an incorrect string is passed', async function () { - await shouldFail(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' })); + await expectFailure(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' })); }); }); it('throws if an unemitted event is requested', async function () { - await shouldFail(expectEvent.inConstruction(this.emitter, 'UnemittedEvent')); + await expectFailure(expectEvent.inConstruction(this.emitter, 'UnemittedEvent')); }); }); @@ -386,25 +386,25 @@ describe('expectEvent', function () { }); it('throws if an unemitted event is requested', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent', + await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent', { value: this.value } )); }); it('throws if an incorrect string is passed', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'String', + await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'String', { value: 'ClosedZeppelin' } )); }); it('throws if an event emitted from other contract is passed', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', + await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', { value: this.value } )); }); it('throws if an incorrect emitter is passed', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', + await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', { value: this.value } )); }); @@ -418,25 +418,25 @@ describe('expectEvent', function () { }); it('throws if an unemitted event is requested', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent', + await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent', { value: this.value } )); }); it('throws if an incorrect string is passed', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString', + await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString', { value: 'ClosedZeppelin' } )); }); it('throws if an event emitted from other contract is passed', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', + await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', { value: this.value } )); }); it('throws if an incorrect emitter is passed', async function () { - await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', + await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', { value: this.value } )); }); diff --git a/test/src/shouldFail.test.js b/test/src/expectFailure.test.js similarity index 55% rename from test/src/shouldFail.test.js rename to test/src/expectFailure.test.js index 250c96c..031e848 100644 --- a/test/src/shouldFail.test.js +++ b/test/src/expectFailure.test.js @@ -1,5 +1,5 @@ const { expect } = require('chai'); -const shouldFail = require('../../src/shouldFail'); +const expectFailure = require('../../src/expectFailure'); const Failer = artifacts.require('Failer'); @@ -12,114 +12,114 @@ async function assertFailure (promise) { expect.fail(); } -describe('shouldFail', function () { +describe('expectFailure', function () { beforeEach(async function () { this.failer = await Failer.new(); }); - describe('shouldFail', function () { + describe('expectFailure', function () { it('rejects if no failure occurs', async function () { - await assertFailure(shouldFail(this.failer.dontFail())); + await assertFailure(expectFailure(this.failer.dontFail())); }); it('accepts a revert', async function () { - await shouldFail(this.failer.failWithRevert()); + await expectFailure(this.failer.failWithRevert()); }); it('accepts a require() revert', async function () { - await shouldFail(this.failer.failRequirement()); + await expectFailure(this.failer.failRequirement()); }); it('accepts a throw', async function () { - await shouldFail(this.failer.failWithThrow()); + await expectFailure(this.failer.failWithThrow()); }); it('accepts an out of gas', async function () { - await shouldFail(this.failer.failWithOutOfGas({ gas: 2000000 })); + await expectFailure(this.failer.failWithOutOfGas({ gas: 2000000 })); }); }); - describe('reverting', function () { + describe('revert', function () { it('rejects if no failure occurs', async function () { - await assertFailure(shouldFail.reverting(this.failer.dontFail())); + await assertFailure(expectFailure.revert(this.failer.dontFail())); }); it('accepts a revert', async function () { - await shouldFail.reverting(this.failer.failWithRevert()); + await expectFailure.revert(this.failer.failWithRevert()); }); it('accepts a require() revert', async function () { - await shouldFail.reverting(this.failer.failRequirement()); + await expectFailure.revert(this.failer.failRequirement()); }); it('rejects a throw', async function () { - await assertFailure(shouldFail.reverting(this.failer.failWithThrow())); + await assertFailure(expectFailure.revert(this.failer.failWithThrow())); }); it('rejects an outOfGas', async function () { - await assertFailure(shouldFail.reverting(this.failer.failWithOutOfGas({ gas: 2000000 }))); + await assertFailure(expectFailure.revert(this.failer.failWithOutOfGas({ gas: 2000000 }))); }); - describe('reverting.withMessage', function () { + describe('revert.withMessage', function () { it('rejects if no failure occurs', async function () { - await assertFailure(shouldFail.reverting.withMessage(this.failer.dontFail())); + await assertFailure(expectFailure.revert.withMessage(this.failer.dontFail())); }); it('accepts a revert with an expected reason', async function () { - await shouldFail.reverting.withMessage(this.failer.failWithRevertReason(), 'Doomed to fail'); + await expectFailure.revert.withMessage(this.failer.failWithRevertReason(), 'Doomed to fail'); }); it('rejects a revert with an unexpected reason', async function () { - await assertFailure(shouldFail.reverting.withMessage(this.failer.failWithRevertReason(), 'Wrong reason')); + await assertFailure(expectFailure.revert.withMessage(this.failer.failWithRevertReason(), 'Wrong reason')); }); it('rejects if no reason string passed', async function () { - await assertFailure(shouldFail.reverting.withMessage(this.failer.failWithRevertReason())); + await assertFailure(expectFailure.revert.withMessage(this.failer.failWithRevertReason())); }); it('accepts require() revert with an expected reason', async function () { - await shouldFail.reverting.withMessage(this.failer.failRequirementWithReason(), 'Unsatisfied'); + await expectFailure.revert.withMessage(this.failer.failRequirementWithReason(), 'Unsatisfied'); }); it('rejects a require() revert with an unexpected reason', async function () { - await assertFailure(shouldFail.reverting.withMessage(this.failer.failRequirementWithReason(), 'Wrong reason')); + await assertFailure(expectFailure.revert.withMessage(this.failer.failRequirementWithReason(), 'Wrong reason')); }); }); }); - describe('throwing', function () { + describe('throw', function () { it('rejects if no failure occurs', async function () { - await assertFailure(shouldFail.throwing(this.failer.dontFail())); + await assertFailure(expectFailure.throw(this.failer.dontFail())); }); it('accepts a throw', async function () { - await shouldFail.throwing(this.failer.failWithThrow()); + await expectFailure.throw(this.failer.failWithThrow()); }); it('rejects a throw', async function () { - await assertFailure(shouldFail.throwing(this.failer.failWithRevert())); + await assertFailure(expectFailure.throw(this.failer.failWithRevert())); }); it('rejects an outOfGas', async function () { - await assertFailure(shouldFail.throwing(this.failer.failWithOutOfGas({ gas: 2000000 }))); + await assertFailure(expectFailure.throw(this.failer.failWithOutOfGas({ gas: 2000000 }))); }); }); describe('outOfGas', function () { it('rejects if no failure occurs', async function () { - await assertFailure(shouldFail.outOfGas(this.failer.dontFail())); + await assertFailure(expectFailure.outOfGas(this.failer.dontFail())); }); it('accepts an out of gas', async function () { - await shouldFail.outOfGas(this.failer.failWithOutOfGas({ gas: 2000000 })); + await expectFailure.outOfGas(this.failer.failWithOutOfGas({ gas: 2000000 })); }); it('rejects a revert', async function () { - await assertFailure(shouldFail.outOfGas(this.failer.failWithRevert())); + await assertFailure(expectFailure.outOfGas(this.failer.failWithRevert())); }); it('rejects a throw', async function () { - await assertFailure(shouldFail.outOfGas(this.failer.failWithThrow())); + await assertFailure(expectFailure.outOfGas(this.failer.failWithThrow())); }); }); }); diff --git a/test/src/send.test.js b/test/src/send.test.js index 56b8380..369e7d9 100644 --- a/test/src/send.test.js +++ b/test/src/send.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); const send = require('../../src/send'); -const shouldFail = require('../../src/shouldFail'); +const expectFailure = require('../../src/expectFailure'); const expectEvent = require('../../src/expectEvent'); const ether = require('../../src/ether'); @@ -27,7 +27,7 @@ contract('send', function ([sender, receiver]) { it('throws if the sender balance is insufficient', async function () { const value = new BN(await web3.eth.getBalance(sender)).add(new BN(1)); - await shouldFail(send.ether(sender, receiver, value)); + await expectFailure(send.ether(sender, receiver, value)); }); it('calls fallback function', async function () { @@ -71,15 +71,15 @@ contract('send', function ([sender, receiver]) { }); it('throws if the number of arguments does not match', async function () { - await shouldFail(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]), opts); + await expectFailure(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]), opts); }); it('throws if the method does not exist', async function () { - await shouldFail(send.transaction(this.acknowledger, 'baz', 'uint256', [3]), opts); + await expectFailure(send.transaction(this.acknowledger, 'baz', 'uint256', [3]), opts); }); it('throws if there is a mismatch in the number of types and values', async function () { - await shouldFail(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]), opts); + await expectFailure(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]), opts); }); } }); diff --git a/test/src/time.test.js b/test/src/time.test.js index 605e062..d4d69eb 100644 --- a/test/src/time.test.js +++ b/test/src/time.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); const time = require('../../src/time'); -const shouldFail = require('../../src/shouldFail'); +const expectFailure = require('../../src/expectFailure'); describe('time', function () { const TOLERANCE_SECONDS = new BN(1); @@ -69,7 +69,7 @@ describe('time', function () { }); it('throws with negative durations', async function () { - await shouldFail(time.increase(-1)); + await expectFailure(time.increase(-1)); }); }); @@ -83,7 +83,7 @@ describe('time', function () { }); it('throws with a time in the past', async function () { - await shouldFail(time.increaseTo(this.start.sub(new BN(30)))); + await expectFailure(time.increaseTo(this.start.sub(new BN(30)))); }); }); }); From f5bf20a86bc453ed137abdc1244d5eb772d57b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 10 May 2019 21:17:01 -0300 Subject: [PATCH 02/13] Fix exports. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 62e2876..7b8dbbe 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ module.exports = { expectEvent: require('./src/expectEvent'), makeInterfaceId: require('./src/makeInterfaceId'), send: require('./src/send'), - shouldFail: require('./src/shouldFail'), + expectFailure: require('./src/expectFailure'), singletons: require('./src/singletons'), time: require('./src/time'), }; From a5afbed81d2ff87fb66b6d02f7bd536b489c6bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Sun, 12 May 2019 16:44:45 -0300 Subject: [PATCH 03/13] Refactor expectRevert and change API. --- .eslintrc | 1 + contracts/Failer.sol | 34 ---- contracts/Reverter.sol | 38 ++++ index.js | 2 +- src/expectFailure.js | 59 ------ src/expectRevert.js | 59 ++++++ .../ganache-core-2.1.x/test/Tested.test.js | 6 +- .../test/Tested.test.js | 6 +- test/src/expectEvent.test.js | 28 +-- test/src/expectFailure.test.js | 125 ------------- test/src/expectRevert.test.js | 171 ++++++++++++++++++ test/src/send.test.js | 10 +- test/src/time.test.js | 6 +- 13 files changed, 298 insertions(+), 247 deletions(-) delete mode 100644 contracts/Failer.sol create mode 100644 contracts/Reverter.sol delete mode 100644 src/expectFailure.js create mode 100644 src/expectRevert.js delete mode 100644 test/src/expectFailure.test.js create mode 100644 test/src/expectRevert.test.js diff --git a/.eslintrc b/.eslintrc index e4cc9f2..3d44292 100644 --- a/.eslintrc +++ b/.eslintrc @@ -33,6 +33,7 @@ "no-dupe-args": "error", "no-dupe-keys": "error", "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], + "no-multi-str": "off", "no-redeclare": ["error", {"builtinGlobals": true}], "no-trailing-spaces": ["error", { "skipBlankLines": false }], "no-undef": "error", diff --git a/contracts/Failer.sol b/contracts/Failer.sol deleted file mode 100644 index 543ac2c..0000000 --- a/contracts/Failer.sol +++ /dev/null @@ -1,34 +0,0 @@ -pragma solidity ^0.4.24; - -contract Failer { - uint256[] private array; - - function dontFail() public pure { - } - - function failWithRevert() public pure { - revert(); - } - - function failWithThrow() public pure { - assert(false); - } - - function failWithRevertReason() public pure { - revert("Doomed to fail"); - } - - function failWithOutOfGas() public { - for (uint256 i = 0; i < 2**200; ++i) { - array.push(i); - } - } - - function failRequirement() public pure { - require(false); - } - - function failRequirementWithReason() public pure { - require(false, "Unsatisfied"); - } -} diff --git a/contracts/Reverter.sol b/contracts/Reverter.sol new file mode 100644 index 0000000..7d4acad --- /dev/null +++ b/contracts/Reverter.sol @@ -0,0 +1,38 @@ +pragma solidity ^0.4.24; + +contract Reverter { + uint256[] private array; + + function dontRevert() public pure { + } + + function revertFromRevert() public pure { + revert(); + } + + function revertFromRevertWithReason() public pure { + revert("Call to revert"); + } + + function revertFromRequire() public pure { + require(false); + } + + function revertFromRequireWithReason() public pure { + require(false, "Failed requirement"); + } + + function revertFromThrow() public pure { + throw; + } + + function revertFromAssert() public pure { + assert(false); + } + + function revertFromOutOfGas() public { + for (uint256 i = 0; i < 2**200; ++i) { + array.push(i); + } + } +} diff --git a/index.js b/index.js index 7b8dbbe..d59fb80 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ module.exports = { expectEvent: require('./src/expectEvent'), makeInterfaceId: require('./src/makeInterfaceId'), send: require('./src/send'), - expectFailure: require('./src/expectFailure'), + expectRevert: require('./src/expectRevert'), singletons: require('./src/singletons'), time: require('./src/time'), }; diff --git a/src/expectFailure.js b/src/expectFailure.js deleted file mode 100644 index 64ac23c..0000000 --- a/src/expectFailure.js +++ /dev/null @@ -1,59 +0,0 @@ -const { web3 } = require('./setup'); - -const { expect } = require('chai'); -const colors = require('ansi-colors'); -const semver = require('semver'); - -async function expectFailureWithMessage (promise, message) { - try { - await promise; - } catch (error) { - if (message) { - expect(error.message).to.include(message, `Wrong failure type, expected '${message}'`); - } else { - expect.fail('Message not provided'); - } - return; - } - - expect.fail('Expected failure not received'); -} - -async function expectFailure (promise) { - try { - await promise; - } catch (error) { - return; - } - expect.fail('Failure not received'); -} - -async function withMessage (promise, message) { - // Find out if current version of ganache-core supports revert reason i.e >= 2.2.0. - // https://github.com/trufflesuite/ganache-core/releases/tag/v2.2.0 - const nodeInfo = await web3.eth.getNodeInfo(); - const matches = /TestRPC\/v([0-9.]+)\/ethereum-js/.exec(nodeInfo); - const warn = function (msg) { - console.log(`${colors.white.bgBlack('openzeppelin-test-helpers')} ${colors.black.bgYellow('WARN')} \ -expectFailure.revert.withMessage: ` + msg); - }; - if (matches === null || !(1 in matches)) { - // warn users and skip reason check. - warn('revert reason checking only supported on Ganache>=2.2.0'); - return expectFailure(promise); - } else if (!semver.satisfies(matches[1], '>=2.2.0')) { - // warn users and skip reason check. - warn(`current version of Ganache (${matches[1]}) doesn't return revert reason.`); - return expectFailure(promise); - } else { - // actually perform revert reason check. - return expectFailureWithMessage(promise, message); - } -} - -expectFailure.revert = (promise) => expectFailureWithMessage(promise, 'revert'); -expectFailure.revert.withMessage = withMessage; -expectFailure.throw = (promise) => expectFailureWithMessage(promise, 'invalid opcode'); -expectFailure.outOfGas = (promise) => expectFailureWithMessage(promise, 'out of gas'); - -module.exports = expectFailure; diff --git a/src/expectRevert.js b/src/expectRevert.js new file mode 100644 index 0000000..af91b5e --- /dev/null +++ b/src/expectRevert.js @@ -0,0 +1,59 @@ +const { web3 } = require('./setup'); + +const { expect } = require('chai'); +const colors = require('ansi-colors'); +const semver = require('semver'); + +async function expectException (promise, expectedErrors) { + try { + await promise; + } catch (error) { + for (const expectedError of expectedErrors) { + expect(error.message).to.include(expectedError, `Wrong failure type, expected '${expectedError}'`); + } + return; + } + + throw Error('Expected failure not received'); +} + +const expectRevert = async function (promise, expectedError) { + if (!expectedError) { + try { await promise; } catch (error) { } + throw Error('No revert reason specified: call expectRevert with the reason string, or use expectRevert.unspecified\ + if your \'require\' statement doesn\'t have one.'); + } + + // Find out if current version of ganache-core supports revert reason i.e >= 2.2.0. + // https://github.com/trufflesuite/ganache-core/releases/tag/v2.2.0 + const nodeInfo = await web3.eth.getNodeInfo(); + const matches = /TestRPC\/v([0-9.]+)\/ethereum-js/.exec(nodeInfo); + + const warn = function (msg) { + console.log(`${colors.white.bgBlack('openzeppelin-test-helpers')} ${colors.black.bgYellow('WARN')} \ + expectRevert: ` + msg); + }; + + let expectedErrors; + + if (matches === null || !(1 in matches)) { + // warn users and skip reason check. + warn('revert reason checking only supported on Ganache v2.2.0 or newer.'); + expectedErrors = ['revert']; + } else if (!semver.satisfies(matches[1], '>=2.2.0')) { + // warn users and skip reason check. + warn(`current version of Ganache (v${matches[1]}) doesn't return revert reason. Use v2.2.0 or newer.`); + expectedErrors = ['revert']; + } else { + // actually perform revert reason check. + expectedErrors = ['revert', expectedError]; + } + + await expectException(promise, expectedErrors); +}; + +expectRevert.assertion = (promise) => expectException(promise, ['invalid opcode']); +expectRevert.outOfGas = (promise) => expectException(promise, ['out of gas']); +expectRevert.unspecified = (promise) => expectException(promise, ['revert']); + +module.exports = expectRevert; diff --git a/test-integration/ganache-core-2.1.x/test/Tested.test.js b/test-integration/ganache-core-2.1.x/test/Tested.test.js index c630f85..daedb05 100644 --- a/test-integration/ganache-core-2.1.x/test/Tested.test.js +++ b/test-integration/ganache-core-2.1.x/test/Tested.test.js @@ -1,10 +1,10 @@ -const { expectFailure } = require('openzeppelin-test-helpers'); +const { expectRevert } = require('openzeppelin-test-helpers'); const { expect } = require('chai'); const Tested = artifacts.require('Tested'); contract('Tested', function (accounts) { - context('expectFailure.revert.withMessage', async function () { + context('expectRevert.revert.withMessage', async function () { beforeEach(async function () { this.contract = await Tested.new(); }) @@ -25,7 +25,7 @@ contract('Tested', function (accounts) { } // With that said, following revert should be accepted without regard to the specified // reason message. - await expectFailure.revert.withMessage(this.contract.failWithRevertReason(), expectedMessage); + await expectRevert.revert.withMessage(this.contract.failWithRevertReason(), expectedMessage); }) }) }) diff --git a/test-integration/simple-project-truffle-5.x/test/Tested.test.js b/test-integration/simple-project-truffle-5.x/test/Tested.test.js index 72cf879..32064e0 100644 --- a/test-integration/simple-project-truffle-5.x/test/Tested.test.js +++ b/test-integration/simple-project-truffle-5.x/test/Tested.test.js @@ -1,4 +1,4 @@ -const { BN, constants, expectEvent, expectFailure } = require('openzeppelin-test-helpers'); +const { BN, constants, expectEvent, expectRevert } = require('openzeppelin-test-helpers'); const Tested = artifacts.require('Tested'); @@ -13,7 +13,7 @@ contract('Tested', function (accounts) { }) it('detect reverts', async function () { - await expectFailure.revert(this.contract.reverts()); + await expectRevert.revert(this.contract.reverts()); }); it('accepts calls with non-zero address', async function () { @@ -22,7 +22,7 @@ contract('Tested', function (accounts) { }); it('reverts with calls with non-zero address', async function () { - await expectFailure.revert(this.contract.nonZeroAddress(constants.ZERO_ADDRESS)); + await expectRevert.revert(this.contract.nonZeroAddress(constants.ZERO_ADDRESS)); }); }); }); diff --git a/test/src/expectEvent.test.js b/test/src/expectEvent.test.js index f1a3ea7..6847dbf 100644 --- a/test/src/expectEvent.test.js +++ b/test/src/expectEvent.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); const expectEvent = require('../../src/expectEvent'); -const expectFailure = require('../../src/expectFailure'); +const expectRevert = require('../../src/expectRevert'); const EventEmitter = artifacts.require('EventEmitter'); const IndirectEventEmitter = artifacts.require('IndirectEventEmitter'); @@ -30,13 +30,13 @@ describe('expectEvent', function () { }); it('throws if a correct JavaScript number is passed', async function () { - await expectFailure( + await expectRevert( expectEvent.inConstruction(this.emitter, 'ShortUint', { value: this.constructionValues.uint }) ); }); it('throws if an incorrect value is passed', async function () { - await expectFailure(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 })); + await expectRevert(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 })); }); }); @@ -46,7 +46,7 @@ describe('expectEvent', function () { }); it('throws if an incorrect value is passed', async function () { - await expectFailure(expectEvent.inConstruction(this.emitter, 'Boolean', + await expectRevert(expectEvent.inConstruction(this.emitter, 'Boolean', { value: !this.constructionValues.boolean } )); }); @@ -58,12 +58,12 @@ describe('expectEvent', function () { }); it('throws if an incorrect string is passed', async function () { - await expectFailure(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' })); + await expectRevert(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' })); }); }); it('throws if an unemitted event is requested', async function () { - await expectFailure(expectEvent.inConstruction(this.emitter, 'UnemittedEvent')); + await expectRevert(expectEvent.inConstruction(this.emitter, 'UnemittedEvent')); }); }); @@ -386,25 +386,25 @@ describe('expectEvent', function () { }); it('throws if an unemitted event is requested', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent', + await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent', { value: this.value } )); }); it('throws if an incorrect string is passed', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'String', + await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'String', { value: 'ClosedZeppelin' } )); }); it('throws if an event emitted from other contract is passed', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', + await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', { value: this.value } )); }); it('throws if an incorrect emitter is passed', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', + await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', { value: this.value } )); }); @@ -418,25 +418,25 @@ describe('expectEvent', function () { }); it('throws if an unemitted event is requested', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent', + await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent', { value: this.value } )); }); it('throws if an incorrect string is passed', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString', + await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString', { value: 'ClosedZeppelin' } )); }); it('throws if an event emitted from other contract is passed', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', + await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', { value: this.value } )); }); it('throws if an incorrect emitter is passed', async function () { - await expectFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', + await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', { value: this.value } )); }); diff --git a/test/src/expectFailure.test.js b/test/src/expectFailure.test.js deleted file mode 100644 index 031e848..0000000 --- a/test/src/expectFailure.test.js +++ /dev/null @@ -1,125 +0,0 @@ -const { expect } = require('chai'); -const expectFailure = require('../../src/expectFailure'); - -const Failer = artifacts.require('Failer'); - -async function assertFailure (promise) { - try { - await promise; - } catch (error) { - return; - } - expect.fail(); -} - -describe('expectFailure', function () { - beforeEach(async function () { - this.failer = await Failer.new(); - }); - - describe('expectFailure', function () { - it('rejects if no failure occurs', async function () { - await assertFailure(expectFailure(this.failer.dontFail())); - }); - - it('accepts a revert', async function () { - await expectFailure(this.failer.failWithRevert()); - }); - - it('accepts a require() revert', async function () { - await expectFailure(this.failer.failRequirement()); - }); - - it('accepts a throw', async function () { - await expectFailure(this.failer.failWithThrow()); - }); - - it('accepts an out of gas', async function () { - await expectFailure(this.failer.failWithOutOfGas({ gas: 2000000 })); - }); - }); - - describe('revert', function () { - it('rejects if no failure occurs', async function () { - await assertFailure(expectFailure.revert(this.failer.dontFail())); - }); - - it('accepts a revert', async function () { - await expectFailure.revert(this.failer.failWithRevert()); - }); - - it('accepts a require() revert', async function () { - await expectFailure.revert(this.failer.failRequirement()); - }); - - it('rejects a throw', async function () { - await assertFailure(expectFailure.revert(this.failer.failWithThrow())); - }); - - it('rejects an outOfGas', async function () { - await assertFailure(expectFailure.revert(this.failer.failWithOutOfGas({ gas: 2000000 }))); - }); - - describe('revert.withMessage', function () { - it('rejects if no failure occurs', async function () { - await assertFailure(expectFailure.revert.withMessage(this.failer.dontFail())); - }); - - it('accepts a revert with an expected reason', async function () { - await expectFailure.revert.withMessage(this.failer.failWithRevertReason(), 'Doomed to fail'); - }); - - it('rejects a revert with an unexpected reason', async function () { - await assertFailure(expectFailure.revert.withMessage(this.failer.failWithRevertReason(), 'Wrong reason')); - }); - - it('rejects if no reason string passed', async function () { - await assertFailure(expectFailure.revert.withMessage(this.failer.failWithRevertReason())); - }); - - it('accepts require() revert with an expected reason', async function () { - await expectFailure.revert.withMessage(this.failer.failRequirementWithReason(), 'Unsatisfied'); - }); - - it('rejects a require() revert with an unexpected reason', async function () { - await assertFailure(expectFailure.revert.withMessage(this.failer.failRequirementWithReason(), 'Wrong reason')); - }); - }); - }); - - describe('throw', function () { - it('rejects if no failure occurs', async function () { - await assertFailure(expectFailure.throw(this.failer.dontFail())); - }); - - it('accepts a throw', async function () { - await expectFailure.throw(this.failer.failWithThrow()); - }); - - it('rejects a throw', async function () { - await assertFailure(expectFailure.throw(this.failer.failWithRevert())); - }); - - it('rejects an outOfGas', async function () { - await assertFailure(expectFailure.throw(this.failer.failWithOutOfGas({ gas: 2000000 }))); - }); - }); - - describe('outOfGas', function () { - it('rejects if no failure occurs', async function () { - await assertFailure(expectFailure.outOfGas(this.failer.dontFail())); - }); - - it('accepts an out of gas', async function () { - await expectFailure.outOfGas(this.failer.failWithOutOfGas({ gas: 2000000 })); - }); - - it('rejects a revert', async function () { - await assertFailure(expectFailure.outOfGas(this.failer.failWithRevert())); - }); - - it('rejects a throw', async function () { - await assertFailure(expectFailure.outOfGas(this.failer.failWithThrow())); - }); - }); -}); diff --git a/test/src/expectRevert.test.js b/test/src/expectRevert.test.js new file mode 100644 index 0000000..85c0c2c --- /dev/null +++ b/test/src/expectRevert.test.js @@ -0,0 +1,171 @@ +const { expect } = require('chai'); +const expectRevert = require('../../src/expectRevert'); + +const Reverter = artifacts.require('Reverter'); + +async function assertFailure (promise) { + try { + await promise; + } catch (error) { + return; + } + expect.fail(); +} + +describe('expectRevert', function () { + beforeEach(async function () { + this.reverter = await Reverter.new(); + }); + + describe('expectRevert', function () { + it('rejects if no revert occurs', async function () { + await assertFailure(expectRevert(this.reverter.dontRevert())); + }); + + it('rejects a revert', async function () { + await assertFailure(expectRevert(this.reverter.revertFromRevert())); + }); + + it('rejects a revert with reason and none expected', async function () { + await assertFailure(expectRevert(this.reverter.revertFromRevertWithReason())); + }); + + it('rejects a revert with incorrect expected reason', async function () { + await assertFailure(expectRevert(this.reverter.revertFromRevertWithReason(), 'Wrong reason')); + }); + + it('accepts a revert with correct expected reason', async function () { + await expectRevert(this.reverter.revertFromRevertWithReason(), 'Call to revert'); + }); + + it('rejects a failed requirement', async function () { + await assertFailure(expectRevert(this.reverter.revertFromRequire())); + }); + + it('rejects a failed requirement with reason and none expected', async function () { + await assertFailure(expectRevert(this.reverter.revertFromRequireWithReason())); + }); + + it('rejects a failed requirement with incorrect expected reason', async function () { + await assertFailure(expectRevert(this.reverter.revertFromRequireWithReason(), 'Wrong reason')); + }); + + it('accepts a failed requirement with correct expected reason', async function () { + await expectRevert(this.reverter.revertFromRequireWithReason(), 'Failed requirement'); + }); + + it('rejects a throw', async function () { + await assertFailure(expectRevert(this.reverter.revertFromThrow())); + }); + + it('rejects a failed assertion', async function () { + await assertFailure(expectRevert(this.reverter.revertFromAssert())); + }); + + it('rejects an outOfGas', async function () { + await assertFailure(expectRevert(this.reverter.revertFromOutOfGas({ gas: 2000000 }))); + }); + }); + + describe('unspecified', function () { + it('rejects if no revert occurs', async function () { + await assertFailure(expectRevert.unspecified(this.reverter.dontRevert())); + }); + + it('accepts a revert', async function () { + await expectRevert.unspecified(this.reverter.revertFromRevert()); + }); + + it('accepts a revert with reason', async function () { + await expectRevert.unspecified(this.reverter.revertFromRevertWithReason()); + }); + + it('accepts a failed requirement', async function () { + await expectRevert.unspecified(this.reverter.revertFromRequire()); + }); + + it('accepts a failed requirement with reason', async function () { + await expectRevert.unspecified(this.reverter.revertFromRequireWithReason()); + }); + + it('accepts a throw', async function () { + await expectRevert.unspecified(this.reverter.revertFromThrow()); + }); + + it('rejects a failed assertion', async function () { + await assertFailure(expectRevert.unspecified(this.reverter.revertFromAssert())); + }); + + it('rejects an outOfGas', async function () { + await assertFailure(expectRevert.unspecified(this.reverter.revertFromOutOfGas({ gas: 2000000 }))); + }); + }); + + describe('assertion', function () { + it('rejects if no revert occurs', async function () { + await assertFailure(expectRevert.assertion(this.reverter.dontRevert())); + }); + + it('rejects a revert', async function () { + await assertFailure(expectRevert.assertion(this.reverter.revertFromRevert())); + }); + + it('rejects a revert with reason', async function () { + await assertFailure(expectRevert.assertion(this.reverter.revertFromRevertWithReason())); + }); + + it('rejects a failed requirement', async function () { + await assertFailure(expectRevert.assertion(this.reverter.revertFromRequire())); + }); + + it('rejects a failed requirement with reason', async function () { + await assertFailure(expectRevert.assertion(this.reverter.revertFromRequireWithReason())); + }); + + it('rejects a throw', async function () { + await assertFailure(expectRevert.assertion(this.reverter.revertFromThrow())); + }); + + it('accepts a failed assertion', async function () { + await expectRevert.assertion(this.reverter.revertFromAssert()); + }); + + it('rejects an outOfGas', async function () { + await assertFailure(expectRevert.assertion(this.reverter.revertFromOutOfGas({ gas: 2000000 }))); + }); + }); + + describe('outOfGas', function () { + it('rejects if no revert occurs', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.dontRevert())); + }); + + it('rejects a revert', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.revertFromRevert())); + }); + + it('rejects a revert with reason', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.revertFromRevertWithReason())); + }); + + it('rejects a failed requirement', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.revertFromRequire())); + }); + + it('rejects a failed requirement with reason', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.revertFromRequireWithReason())); + }); + + it('rejects a throw', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.revertFromThrow())); + }); + + it('accepts a failed assertion', async function () { + await assertFailure(expectRevert.outOfGas(this.reverter.revertFromAssert())); + }); + + it('accets an outOfGas', async function () { + await expectRevert.outOfGas(this.reverter.revertFromOutOfGas({ gas: 2000000 })); + }); + }); +}); diff --git a/test/src/send.test.js b/test/src/send.test.js index 369e7d9..7b140f0 100644 --- a/test/src/send.test.js +++ b/test/src/send.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); const send = require('../../src/send'); -const expectFailure = require('../../src/expectFailure'); +const expectRevert = require('../../src/expectRevert'); const expectEvent = require('../../src/expectEvent'); const ether = require('../../src/ether'); @@ -27,7 +27,7 @@ contract('send', function ([sender, receiver]) { it('throws if the sender balance is insufficient', async function () { const value = new BN(await web3.eth.getBalance(sender)).add(new BN(1)); - await expectFailure(send.ether(sender, receiver, value)); + await expectRevert(send.ether(sender, receiver, value)); }); it('calls fallback function', async function () { @@ -71,15 +71,15 @@ contract('send', function ([sender, receiver]) { }); it('throws if the number of arguments does not match', async function () { - await expectFailure(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]), opts); + await expectRevert(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]), opts); }); it('throws if the method does not exist', async function () { - await expectFailure(send.transaction(this.acknowledger, 'baz', 'uint256', [3]), opts); + await expectRevert(send.transaction(this.acknowledger, 'baz', 'uint256', [3]), opts); }); it('throws if there is a mismatch in the number of types and values', async function () { - await expectFailure(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]), opts); + await expectRevert(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]), opts); }); } }); diff --git a/test/src/time.test.js b/test/src/time.test.js index d4d69eb..695f9a4 100644 --- a/test/src/time.test.js +++ b/test/src/time.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); const time = require('../../src/time'); -const expectFailure = require('../../src/expectFailure'); +const expectRevert = require('../../src/expectRevert'); describe('time', function () { const TOLERANCE_SECONDS = new BN(1); @@ -69,7 +69,7 @@ describe('time', function () { }); it('throws with negative durations', async function () { - await expectFailure(time.increase(-1)); + await expectRevert(time.increase(-1)); }); }); @@ -83,7 +83,7 @@ describe('time', function () { }); it('throws with a time in the past', async function () { - await expectFailure(time.increaseTo(this.start.sub(new BN(30)))); + await expectRevert(time.increaseTo(this.start.sub(new BN(30)))); }); }); }); From c244fb41b793b02ba2082dae4003cd2cc431a43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 13 May 2019 15:18:32 -0300 Subject: [PATCH 04/13] Update src/expectRevert.js Co-Authored-By: Francisco Giordano --- src/expectRevert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expectRevert.js b/src/expectRevert.js index af91b5e..d56fea5 100644 --- a/src/expectRevert.js +++ b/src/expectRevert.js @@ -19,7 +19,7 @@ async function expectException (promise, expectedErrors) { const expectRevert = async function (promise, expectedError) { if (!expectedError) { - try { await promise; } catch (error) { } + promise.catch(() => { }); throw Error('No revert reason specified: call expectRevert with the reason string, or use expectRevert.unspecified\ if your \'require\' statement doesn\'t have one.'); } From 82c8ad3a349f3c4e12bb26e3a52df2e93a2801b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 13 May 2019 16:34:41 -0300 Subject: [PATCH 05/13] Update CHANGELOG.md Co-Authored-By: Francisco Giordano --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b55fb75..1b3093f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ * `shouldFail.reverting.withMessage` fails if no error string is provided. ([#28](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/28) * Rename `makeInterfaceId` to `makeInterfaceId.ERC165`, and add `makeInterfaceId.ERC1820`. ([#21](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/21) * Add possibility to configure a custom web3 instance. ([#38](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/38)) - * Rename `shouldFail` to `expectFailure`. ([#39](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/39)) + * Replace `shouldFail` with `expectRevert`, with an improved API. ([#39](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/39)) #### How to upgrade from 0.3 - Change all occurences of `makeInterfaceId` to `makeInterfaceId.ERC165`. From f59f24a3d520e8a4a0c648617d58191d78b9867f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 13 May 2019 16:35:16 -0300 Subject: [PATCH 06/13] Update CHANGELOG.md Co-Authored-By: Francisco Giordano --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b3093f..32add2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,14 @@ #### How to upgrade from 0.3 - Change all occurences of `makeInterfaceId` to `makeInterfaceId.ERC165`. -- Some uses of `shouldFail.reverting.withMessage` may fail now. This means it was being used incorrectly and an error string to match against should be added. Alternatively, if the error message is unknown, use `shouldFail.reverting` instead. +- The `shouldFail` module has been renamed to `expectRevert`, and `reverting.withMessage` is now the main module export. + +| 0.3 | 0.4 | +| ---------------------------------- | ---------------------------- | +| `shouldFail.reverting.withMessage` | `expectRevert` | +| `shouldFail.reverting` | `expectRevert.unspecified` | +| `shouldFail.throwing` | `expectRevert.invalidOpcode` | +| `shouldFail.outOfGas` | `expectRevert.outOfGas` | ## 0.3.2 (2019-04-10) * Update ERC1820Registry address. ([#26](https://github.com/OpenZeppelin/openzeppelin-test-helpers/pull/26)) From 7cc4db3f06abd8ed31fd5de0071c42ea7d93dd48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 13 May 2019 16:35:47 -0300 Subject: [PATCH 07/13] Update src/expectRevert.js Co-Authored-By: Francisco Giordano --- src/expectRevert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expectRevert.js b/src/expectRevert.js index d56fea5..ededa9a 100644 --- a/src/expectRevert.js +++ b/src/expectRevert.js @@ -40,7 +40,7 @@ const expectRevert = async function (promise, expectedError) { // warn users and skip reason check. warn('revert reason checking only supported on Ganache v2.2.0 or newer.'); expectedErrors = ['revert']; - } else if (!semver.satisfies(matches[1], '>=2.2.0')) { + } else if (!semver.gt(matches[1], '2.2.0')) { // warn users and skip reason check. warn(`current version of Ganache (v${matches[1]}) doesn't return revert reason. Use v2.2.0 or newer.`); expectedErrors = ['revert']; From 8bff5f072c83ebe5c35b25975525ea2ade37809e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 13 May 2019 16:41:55 -0300 Subject: [PATCH 08/13] Update src/expectRevert.js Co-Authored-By: Francisco Giordano --- src/expectRevert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expectRevert.js b/src/expectRevert.js index ededa9a..824b8db 100644 --- a/src/expectRevert.js +++ b/src/expectRevert.js @@ -40,7 +40,7 @@ const expectRevert = async function (promise, expectedError) { // warn users and skip reason check. warn('revert reason checking only supported on Ganache v2.2.0 or newer.'); expectedErrors = ['revert']; - } else if (!semver.gt(matches[1], '2.2.0')) { + } else if (!semver.gte(matches[1], '2.2.0')) { // warn users and skip reason check. warn(`current version of Ganache (v${matches[1]}) doesn't return revert reason. Use v2.2.0 or newer.`); expectedErrors = ['revert']; From 65f2132c67f77092076eab53471081a3c71326db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 16 May 2019 13:22:21 -0300 Subject: [PATCH 09/13] Fix output message. --- src/expectRevert.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expectRevert.js b/src/expectRevert.js index af91b5e..38c4ddc 100644 --- a/src/expectRevert.js +++ b/src/expectRevert.js @@ -20,8 +20,8 @@ async function expectException (promise, expectedErrors) { const expectRevert = async function (promise, expectedError) { if (!expectedError) { try { await promise; } catch (error) { } - throw Error('No revert reason specified: call expectRevert with the reason string, or use expectRevert.unspecified\ - if your \'require\' statement doesn\'t have one.'); + throw Error('No revert reason specified: call expectRevert with the reason string, or use expectRevert.unspecified \ +if your \'require\' statement doesn\'t have one.'); } // Find out if current version of ganache-core supports revert reason i.e >= 2.2.0. From 0c60e8ef8302f76c4df81d865c23e6d7616f5efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 16 May 2019 14:12:59 -0300 Subject: [PATCH 10/13] Add assertFailure helper. --- test/helpers/assertFailure.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/helpers/assertFailure.js diff --git a/test/helpers/assertFailure.js b/test/helpers/assertFailure.js new file mode 100644 index 0000000..f5a63c4 --- /dev/null +++ b/test/helpers/assertFailure.js @@ -0,0 +1,12 @@ +const { expect } = require('chai'); + +async function assertFailure (promise) { + try { + await promise; + } catch (error) { + return; + } + expect.fail(); +} + +module.exports = assertFailure; From ac16e19132bc7369377672d808835f2b84c621d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 16 May 2019 14:16:53 -0300 Subject: [PATCH 11/13] Update tests and integration tests to use the new API. --- src/expectRevert.js | 23 ++++++--------- .../ganache-core-2.1.x/test/Tested.test.js | 4 +-- .../test/Tested.test.js | 4 +-- test/src/expectEvent.test.js | 28 +++++++++---------- test/src/expectRevert.test.js | 11 +------- test/src/send.test.js | 10 +++---- test/src/time.test.js | 6 ++-- 7 files changed, 35 insertions(+), 51 deletions(-) diff --git a/src/expectRevert.js b/src/expectRevert.js index 38c4ddc..c09eab8 100644 --- a/src/expectRevert.js +++ b/src/expectRevert.js @@ -4,13 +4,11 @@ const { expect } = require('chai'); const colors = require('ansi-colors'); const semver = require('semver'); -async function expectException (promise, expectedErrors) { +async function expectException (promise, expectedError) { try { await promise; } catch (error) { - for (const expectedError of expectedErrors) { - expect(error.message).to.include(expectedError, `Wrong failure type, expected '${expectedError}'`); - } + expect(error.message).to.include(expectedError, `Wrong failure type, expected '${expectedError}'`); return; } @@ -34,26 +32,21 @@ if your \'require\' statement doesn\'t have one.'); expectRevert: ` + msg); }; - let expectedErrors; - if (matches === null || !(1 in matches)) { // warn users and skip reason check. warn('revert reason checking only supported on Ganache v2.2.0 or newer.'); - expectedErrors = ['revert']; + expectedError = 'revert'; } else if (!semver.satisfies(matches[1], '>=2.2.0')) { // warn users and skip reason check. warn(`current version of Ganache (v${matches[1]}) doesn't return revert reason. Use v2.2.0 or newer.`); - expectedErrors = ['revert']; - } else { - // actually perform revert reason check. - expectedErrors = ['revert', expectedError]; + expectedError = 'revert'; } - await expectException(promise, expectedErrors); + await expectException(promise, expectedError); }; -expectRevert.assertion = (promise) => expectException(promise, ['invalid opcode']); -expectRevert.outOfGas = (promise) => expectException(promise, ['out of gas']); -expectRevert.unspecified = (promise) => expectException(promise, ['revert']); +expectRevert.assertion = (promise) => expectException(promise, 'invalid opcode'); +expectRevert.outOfGas = (promise) => expectException(promise, 'out of gas'); +expectRevert.unspecified = (promise) => expectException(promise, 'revert'); module.exports = expectRevert; diff --git a/test-integration/ganache-core-2.1.x/test/Tested.test.js b/test-integration/ganache-core-2.1.x/test/Tested.test.js index daedb05..108f2ed 100644 --- a/test-integration/ganache-core-2.1.x/test/Tested.test.js +++ b/test-integration/ganache-core-2.1.x/test/Tested.test.js @@ -4,7 +4,7 @@ const { expect } = require('chai'); const Tested = artifacts.require('Tested'); contract('Tested', function (accounts) { - context('expectRevert.revert.withMessage', async function () { + context('expectRevert', async function () { beforeEach(async function () { this.contract = await Tested.new(); }) @@ -25,7 +25,7 @@ contract('Tested', function (accounts) { } // With that said, following revert should be accepted without regard to the specified // reason message. - await expectRevert.revert.withMessage(this.contract.failWithRevertReason(), expectedMessage); + await expectRevert(this.contract.failWithRevertReason(), expectedMessage); }) }) }) diff --git a/test-integration/simple-project-truffle-5.x/test/Tested.test.js b/test-integration/simple-project-truffle-5.x/test/Tested.test.js index 32064e0..410f25b 100644 --- a/test-integration/simple-project-truffle-5.x/test/Tested.test.js +++ b/test-integration/simple-project-truffle-5.x/test/Tested.test.js @@ -13,7 +13,7 @@ contract('Tested', function (accounts) { }) it('detect reverts', async function () { - await expectRevert.revert(this.contract.reverts()); + await expectRevert.unspecified(this.contract.reverts()); }); it('accepts calls with non-zero address', async function () { @@ -22,7 +22,7 @@ contract('Tested', function (accounts) { }); it('reverts with calls with non-zero address', async function () { - await expectRevert.revert(this.contract.nonZeroAddress(constants.ZERO_ADDRESS)); + await expectRevert.unspecified(this.contract.nonZeroAddress(constants.ZERO_ADDRESS)); }); }); }); diff --git a/test/src/expectEvent.test.js b/test/src/expectEvent.test.js index 6847dbf..e80eb7a 100644 --- a/test/src/expectEvent.test.js +++ b/test/src/expectEvent.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); +const assertFailure = require('../helpers/assertFailure'); const expectEvent = require('../../src/expectEvent'); -const expectRevert = require('../../src/expectRevert'); const EventEmitter = artifacts.require('EventEmitter'); const IndirectEventEmitter = artifacts.require('IndirectEventEmitter'); @@ -30,13 +30,13 @@ describe('expectEvent', function () { }); it('throws if a correct JavaScript number is passed', async function () { - await expectRevert( + await assertFailure( expectEvent.inConstruction(this.emitter, 'ShortUint', { value: this.constructionValues.uint }) ); }); it('throws if an incorrect value is passed', async function () { - await expectRevert(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 })); + await assertFailure(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 })); }); }); @@ -46,7 +46,7 @@ describe('expectEvent', function () { }); it('throws if an incorrect value is passed', async function () { - await expectRevert(expectEvent.inConstruction(this.emitter, 'Boolean', + await assertFailure(expectEvent.inConstruction(this.emitter, 'Boolean', { value: !this.constructionValues.boolean } )); }); @@ -58,12 +58,12 @@ describe('expectEvent', function () { }); it('throws if an incorrect string is passed', async function () { - await expectRevert(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' })); + await assertFailure(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' })); }); }); it('throws if an unemitted event is requested', async function () { - await expectRevert(expectEvent.inConstruction(this.emitter, 'UnemittedEvent')); + await assertFailure(expectEvent.inConstruction(this.emitter, 'UnemittedEvent')); }); }); @@ -386,25 +386,25 @@ describe('expectEvent', function () { }); it('throws if an unemitted event is requested', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent', + await assertFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent', { value: this.value } )); }); it('throws if an incorrect string is passed', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'String', + await assertFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'String', { value: 'ClosedZeppelin' } )); }); it('throws if an event emitted from other contract is passed', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', + await assertFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', { value: this.value } )); }); it('throws if an incorrect emitter is passed', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', + await assertFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', { value: this.value } )); }); @@ -418,25 +418,25 @@ describe('expectEvent', function () { }); it('throws if an unemitted event is requested', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent', + await assertFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent', { value: this.value } )); }); it('throws if an incorrect string is passed', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString', + await assertFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString', { value: 'ClosedZeppelin' } )); }); it('throws if an event emitted from other contract is passed', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', + await assertFailure(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String', { value: this.value } )); }); it('throws if an incorrect emitter is passed', async function () { - await expectRevert(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', + await assertFailure(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString', { value: this.value } )); }); diff --git a/test/src/expectRevert.test.js b/test/src/expectRevert.test.js index 85c0c2c..2a5547b 100644 --- a/test/src/expectRevert.test.js +++ b/test/src/expectRevert.test.js @@ -1,17 +1,8 @@ -const { expect } = require('chai'); +const assertFailure = require('../helpers/assertFailure'); const expectRevert = require('../../src/expectRevert'); const Reverter = artifacts.require('Reverter'); -async function assertFailure (promise) { - try { - await promise; - } catch (error) { - return; - } - expect.fail(); -} - describe('expectRevert', function () { beforeEach(async function () { this.reverter = await Reverter.new(); diff --git a/test/src/send.test.js b/test/src/send.test.js index 7b140f0..91fc327 100644 --- a/test/src/send.test.js +++ b/test/src/send.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); +const assertFailure = require('../helpers/assertFailure'); const send = require('../../src/send'); -const expectRevert = require('../../src/expectRevert'); const expectEvent = require('../../src/expectEvent'); const ether = require('../../src/ether'); @@ -27,7 +27,7 @@ contract('send', function ([sender, receiver]) { it('throws if the sender balance is insufficient', async function () { const value = new BN(await web3.eth.getBalance(sender)).add(new BN(1)); - await expectRevert(send.ether(sender, receiver, value)); + await assertFailure(send.ether(sender, receiver, value)); }); it('calls fallback function', async function () { @@ -71,15 +71,15 @@ contract('send', function ([sender, receiver]) { }); it('throws if the number of arguments does not match', async function () { - await expectRevert(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]), opts); + await assertFailure(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]), opts); }); it('throws if the method does not exist', async function () { - await expectRevert(send.transaction(this.acknowledger, 'baz', 'uint256', [3]), opts); + await assertFailure(send.transaction(this.acknowledger, 'baz', 'uint256', [3]), opts); }); it('throws if there is a mismatch in the number of types and values', async function () { - await expectRevert(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]), opts); + await assertFailure(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]), opts); }); } }); diff --git a/test/src/time.test.js b/test/src/time.test.js index 695f9a4..971d24a 100644 --- a/test/src/time.test.js +++ b/test/src/time.test.js @@ -1,7 +1,7 @@ const { BN } = require('../../src/setup'); const { expect } = require('chai'); +const assertFailure = require('../helpers/assertFailure'); const time = require('../../src/time'); -const expectRevert = require('../../src/expectRevert'); describe('time', function () { const TOLERANCE_SECONDS = new BN(1); @@ -69,7 +69,7 @@ describe('time', function () { }); it('throws with negative durations', async function () { - await expectRevert(time.increase(-1)); + await assertFailure(time.increase(-1)); }); }); @@ -83,7 +83,7 @@ describe('time', function () { }); it('throws with a time in the past', async function () { - await expectRevert(time.increaseTo(this.start.sub(new BN(30)))); + await assertFailure(time.increaseTo(this.start.sub(new BN(30)))); }); }); }); From 0218e515e4389c53aba509dbcbaa9fd09591f41d Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 16 May 2019 16:22:31 -0300 Subject: [PATCH 12/13] update documentation for expectRevert --- README.md | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8f8d4f1..2181e33 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ npm install --save-dev openzeppelin-test-helpers ```javascript // Import all required modules from openzeppelin-test-helpers -const { BN, constants, expectEvent, expectFailure } = require('openzeppelin-test-helpers'); +const { BN, constants, expectEvent, expectRevert } = require('openzeppelin-test-helpers'); // Import preferred chai flavor: both expect and should are supported const { expect } = require('chai'); @@ -30,7 +30,7 @@ contract('ERC20', ([sender, receiver]) => { it('reverts when transferring tokens to the zero address', async function () { // Edge cases that trigger a require statement can be tested for, optionally checking the revert reason as well - await expectFailure.revert(this.erc20.transfer(constants.ZERO_ADDRESS, this.value, { from: sender })); + await expectRevert.unspecified(this.erc20.transfer(constants.ZERO_ADDRESS, this.value, { from: sender })); }); it('emits a Transfer event on successful transfers', async function () { @@ -177,14 +177,11 @@ A chai [should](https://www.chaijs.com/api/bdd/) instance, containing the `bignu --- -### expectFailure -Collection of assertions for failures (similar to [chai's `throw`](https://www.chaijs.com/api/bdd/#method_throw)). `expectFailure` will accept any exception type, but more specific functions exist and their usage is encouraged. +### expectRevert +Collection of assertions for transaction errors (similar to [chai's `throw`](https://www.chaijs.com/api/bdd/#method_throw)). -#### async expectFailure.revert (promise) -Only accepts failures caused due to an EVM revert (e.g. a failed `require`). - -#### async expectFailure.revert.withMessage (promise, message) -Like `expectFailure.revert`, this helper only accepts failures caused due to an EVM revert (e.g. a failed `require`). Furthermore, it checks whether revert reason string includes passed `message`. For example: +#### async expectRevert (promise, message) +This helper asserts that `promise` was rejected due to a reverted transaction, and it will check that the revert reason includes `message`. Use `expectRevert.unspecified` when the revert reason is unknown. For example: ```solidity contract Owned { @@ -203,7 +200,7 @@ contract Owned { Can be tested as follows: ```javascript -const { expectFailure } = require('openzeppelin-test-helpers'); +const { expectRevert } = require('openzeppelin-test-helpers'); const Owned = artifacts.require('Owned'); @@ -214,19 +211,20 @@ contract('Owned', ([owner, other]) => { describe('doOwnerOperation', function() { it('Fails when called by a non-owner account', async function () { - await expectFailure.revert.withMessage(this.owned.doOwnerOperation({ from: other }), "Unauthorized"); + await expectRevert(this.owned.doOwnerOperation({ from: other }), "Unauthorized"); }); }); ... ``` -Use this helper to specify the expected error message, when you're testing a function that can revert for multiple reasons. +#### async expectRevert.unspecified (promise) +This helper asserts that `promise` was rejected due to a reverted transaction caused by a `require` or `revert` statement. -#### async expectFailure.throw (promise) -Only accepts failures due to a failed `assert` (which executes an invalid opcode). +#### async expectRevert.assertion (promise) +This helper asserts that `promise` was rejected due to a reverted transaction caused by an `assert` statement or an invalid opcode. -#### async expectFailure.outOfGas (promise) -Only accepts failures due to the transaction running out of gas. +#### async expectRevert.outOfGas (promise) +This helper asserts that `promise` was rejected due to a a transaction running out of gas. --- From b7c7525cac21a32b274754f7dc090f3b16f2d3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 16 May 2019 16:35:21 -0300 Subject: [PATCH 13/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2181e33..eba9fcd 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,7 @@ This helper asserts that `promise` was rejected due to a reverted transaction ca This helper asserts that `promise` was rejected due to a reverted transaction caused by an `assert` statement or an invalid opcode. #### async expectRevert.outOfGas (promise) -This helper asserts that `promise` was rejected due to a a transaction running out of gas. +This helper asserts that `promise` was rejected due to a transaction running out of gas. ---