/ utils / testUtils.js
testUtils.js
  1  
  2  // This has been tested with the real Ethereum network and Testrpc.
  3  // Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9
  4  exports.assertReverts = (contractMethodCall, maxGasAvailable) => {
  5      return new Promise((resolve, reject) => {
  6          try {
  7              resolve(contractMethodCall())
  8          } catch (error) {
  9              reject(error)
 10          }
 11      })
 12          .then(tx => {
 13              assert.equal(tx.receipt.gasUsed, maxGasAvailable, "tx successful, the max gas available was not consumed")
 14          })
 15          .catch(error => {
 16              if ((error + "").indexOf("invalid opcode") < 0 && (error + "").indexOf("out of gas") < 0) {
 17                  // Checks if the error is from TestRpc. If it is then ignore it.
 18                  // Otherwise relay/throw the error produced by the above assertion.
 19                  // Note that no error is thrown when using a real Ethereum network AND the assertion above is true.
 20                  throw error
 21              }
 22          })
 23  }
 24  
 25  exports.listenForEvent = event => new Promise((resolve, reject) => {
 26      event({}, (error, response) => {
 27          if (!error) {
 28              resolve(response.args)
 29          } else {
 30              reject(error)
 31          }
 32          event.stopWatching()
 33      })
 34  });
 35  
 36  exports.eventValues = (receipt, eventName) => {
 37      if(receipt.events[eventName])
 38          return receipt.events[eventName].returnValues;
 39  }
 40  
 41  exports.addressToBytes32 = (address) => {
 42      const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + address.slice(2);
 43      return "0x" + stringed.substring(stringed.length - 64, stringed.length); 
 44  }
 45  
 46  
 47  // OpenZeppelin's expectThrow helper -
 48  // Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
 49  exports.expectThrow = async promise => {
 50      try {
 51        await promise;
 52      } catch (error) {
 53        // TODO: Check jump destination to destinguish between a throw
 54        //       and an actual invalid jump.
 55        const invalidOpcode = error.message.search('invalid opcode') >= 0;
 56        // TODO: When we contract A calls contract B, and B throws, instead
 57        //       of an 'invalid jump', we get an 'out of gas' error. How do
 58        //       we distinguish this from an actual out of gas event? (The
 59        //       testrpc log actually show an 'invalid jump' event.)
 60        const outOfGas = error.message.search('out of gas') >= 0;
 61        const revert = error.message.search('revert') >= 0;
 62        assert(
 63          invalidOpcode || outOfGas || revert,
 64          'Expected throw, got \'' + error + '\' instead',
 65        );
 66        return;
 67      }
 68      assert.fail('Expected throw not received');
 69    };
 70  
 71    
 72  
 73  exports.assertJump = (error) => {
 74      assert(error.message.search('revert') > -1, 'Revert should happen');
 75  }
 76  
 77  
 78  var callbackToResolve = function (resolve, reject) {
 79      return function (error, value) {
 80              if (error) {
 81                  reject(error);
 82              } else {
 83                  resolve(value);
 84              }
 85          };
 86  };
 87  
 88  exports.promisify = (func) =>
 89      (...args) => {
 90          return new Promise((resolve, reject) => {
 91          const callback = (err, data) => err ? reject(err) : resolve(data);
 92          func.apply(this, [...args, callback]);
 93          });
 94      }
 95          
 96  
 97  // This has been tested with the real Ethereum network and Testrpc.
 98  // Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9
 99  exports.assertReverts = (contractMethodCall, maxGasAvailable) => {
100      return new Promise((resolve, reject) => {
101          try {
102              resolve(contractMethodCall())
103          } catch (error) {
104              reject(error)
105          }
106      })
107          .then(tx => {
108              assert.equal(tx.receipt.gasUsed, maxGasAvailable, "tx successful, the max gas available was not consumed")
109          })
110          .catch(error => {
111              if ((error + "").indexOf("invalid opcode") < 0 && (error + "").indexOf("out of gas") < 0) {
112                  // Checks if the error is from TestRpc. If it is then ignore it.
113                  // Otherwise relay/throw the error produced by the above assertion.
114                  // Note that no error is thrown when using a real Ethereum network AND the assertion above is true.
115                  throw error
116              }
117          })
118  }
119  
120  exports.listenForEvent = event => new Promise((resolve, reject) => {
121      event({}, (error, response) => {
122          if (!error) {
123              resolve(response.args)
124          } else {
125              reject(error)
126          }
127          event.stopWatching()
128      })
129  });
130  
131  exports.eventValues = (receipt, eventName) => {
132      if(receipt.events[eventName])
133          return receipt.events[eventName].returnValues;
134  }
135  
136  exports.addressToBytes32 = (address) => {
137      const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + address.slice(2);
138      return "0x" + stringed.substring(stringed.length - 64, stringed.length); 
139  }
140  
141  
142  // OpenZeppelin's expectThrow helper -
143  // Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
144  exports.expectThrow = async promise => {
145      try {
146        await promise;
147      } catch (error) {
148        // TODO: Check jump destination to destinguish between a throw
149        //       and an actual invalid jump.
150        const invalidOpcode = error.message.search('invalid opcode') >= 0;
151        // TODO: When we contract A calls contract B, and B throws, instead
152        //       of an 'invalid jump', we get an 'out of gas' error. How do
153        //       we distinguish this from an actual out of gas event? (The
154        //       testrpc log actually show an 'invalid jump' event.)
155        const outOfGas = error.message.search('out of gas') >= 0;
156        const revert = error.message.search('revert') >= 0;
157        assert(
158          invalidOpcode || outOfGas || revert,
159          'Expected throw, got \'' + error + '\' instead',
160        );
161        return;
162      }
163      assert.fail('Expected throw not received');
164    };
165  
166  exports.assertJump = (error) => {
167      assert(error.message.search('revert') > -1, 'Revert should happen');
168  }
169  
170  var callbackToResolve = function (resolve, reject) {
171      return function (error, value) {
172              if (error) {
173                  reject(error);
174              } else {
175                  resolve(value);
176              }
177          };
178  };
179  
180  exports.promisify = (func) =>
181      (...args) => {
182          return new Promise((resolve, reject) => {
183          const callback = (err, data) => err ? reject(err) : resolve(data);
184          func.apply(this, [...args, callback]);
185          });
186      }
187      
188  exports.zeroAddress = '0x0000000000000000000000000000000000000000';
189  exports.zeroBytes32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
190  exports.timeUnits = {
191      seconds: 1,
192      minutes: 60,
193      hours: 60 * 60,
194      days: 24 * 60 * 60,
195      weeks: 7 * 24 * 60 * 60,
196      years: 365 * 24 * 60 * 60
197  }
198  
199  exports.ensureException = function(error) {
200      assert(isException(error), error.toString());
201  };
202  
203  function isException(error) {
204      let strError = error.toString();
205      return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
206  }
207  
208  exports.increaseTime = async (amount) => {
209      return new Promise(function(resolve, reject) {
210        web3.currentProvider.sendAsync(
211          {
212            jsonrpc: '2.0',
213            method: 'evm_increaseTime',
214            params: [+amount],
215            id: new Date().getSeconds()
216          },
217          async (error) => {
218            if (error) {
219              console.log(error);
220              return reject(err);
221            }
222            await web3.currentProvider.sendAsync(
223              {
224                jsonrpc: '2.0',
225                method: 'evm_mine',
226                params: [],
227                id: new Date().getSeconds()
228              }, (error) => {
229                if (error) {
230                  console.log(error);
231                  return reject(err);
232                }
233                resolve();
234              }
235            )
236          }
237        )
238      });
239  }