https://mochajs.org/ 學習網址: https://www.jianshu.com/p/9c78548caffa https://www.jb51.net/article/106463.htm 在truffle框架的簡單使用中,咱們瞭解到它的測試模塊是包裝了mocha測試框架的,在這裏咱們選擇cryptopunks的truffle例子來相應講解:javascript
https://github.com/larvalabs/cryptopunkshtml
爲何要使用mocha這個測試模塊:前端
當咱們在開發,咱們每每會有如下的問題:java
參考:https://blog.csdn.net/imwebteam/article/details/53310958node
當一份需求來了, 開發人員每每不能百分百的理解需求的內容(拋棄產品本身變動需求的可能性。。),這每每會讓開發人員開發出的功能會有跟需求有所差異,這會帶來額外的工做量git
什麼是開發和測試脫節,說的是,當開發人員按照本身的想法開發完了一個需求。而後測試人員也按照本身的想法去測試這個需求,而後因爲雙方的分歧,致使測試認爲開發有bug,開發認爲測試是sb.github
那麼如何解決上面的問題呢?web
答案就是 選擇一種軟件敏捷開發模式npm
目前比較流行的開發模式有兩種: TDD 和 BDDjson
兩種方式各有其特色,咱們一般選擇的是BDD的方式
爲了方便咱們編寫測試用例,咱們須要使用一些前端測試用例工具——mocha
在這個例子中咱們可以看見在其的test文件夾中寫了一些測試文件,好比咱們以cryptopunksmarket-setinitia.jsl這個文件爲例,看cryptopunks測試代碼cryptopunksmarket-setinitial.js
(1)Truffle測試框架學習:
參考:http://www.blockchainbrother.com/article/2082
Truffle 使用 Mocha 測試框架 和 Chai 斷言來給你提供一個可靠的框架編寫JavaScript測試。這裏須要注意到的一個很大的不一樣是它使用了contract()測試套件替代了describe()測試套件,這個函數基本和 describe() 同樣,只不過它能夠啓用clean-room 功能. 其過程以下:
(2)後面想要使用測試框架mocha,可是又不想使用truffle,因此就來學習這個框架怎麼單獨使用了,下面就是學習的過程:
固然,首先要安裝:
使用npm全局安裝:
npm install --g mocha
或者僅僅只是安裝在某個模塊:
npm install --save mocha
而後你就可使用了
1.要測試上面的代碼是否對的,所以就要編寫測試腳本,測試腳本與所要測試的源碼腳本同名,可是後綴名爲 .test.js或 .spec.js, 如:xx.test.js 或 xx.spec.js
2.測試腳本能夠包含一個或多個describe塊,describe塊稱爲 "測試套件",表示一組相關的測試,它是一個函數,有兩個參數,第一個參數是測試套件的名稱,第二個參數是一個實際執行的函數。
每一個describe塊也能夠包含一個或多個it塊,it塊稱爲 「測試用例",表示一個單獨的測試,是測試的最小單位,它也是一個函數,第一個參數也是測試用例的名稱,第二個參數是一個實際執行的函數,it塊之間是同步運行的。
describe 和 it 大量嵌套後,就造成了一顆樹。樹的非葉子節點都是測試集合,葉子節點即 it ,就是測試用例。
注意,若是一個describe 裏面沒有 it (好比下面:), Mocha將不會執行這個 describe。
3.理解斷言庫
學習文檔:http://www.chaijs.com
斷言庫能夠理解爲比較函數,也就是斷言函數是否和預期一致,若是一致則表示測試經過,若是不一致表示測試失敗。mocha自己是不包括斷言庫的,因此必須引入第三方斷言庫的,目前比較受歡迎的斷言庫有 should.js, expect.js, chai.
should.js是BDD風格
expect.js是expect風格的斷言
//下面介紹的是chai
chai的expect(), assert() 和 should的斷言
Mocha默認使用的是BDD的風格。expect和should都是BDD的風格,兩者使用相同的鏈式語言來組織斷言的,但不一樣在於他們初始化斷言的方式,expect使用
構造函數來建立斷言對象實例,而should經過爲 Object.prototype新增方法來實現斷言(should不支持IE),expect直接指向 chai.expect,
should則是 chai.should();
上面的代碼中 expect 是斷言的意思,該做用是判斷源碼的實際執行結果與預期結果是否一致,若是不一致就拋出一個錯誤
三種的使用方法簡單以下所示:
var expect = require('chai').expect;
expect(2).to.be.equal(2);
var assert = require('chai').
assert;
assert.equal((await contract.totalSupply()).toNumber(), 10);
var should = require('chai').should();
cookies.should.not.be.empty;
cookies.id.should.equal('10001','not equal to 10001');
所以在執行上面代碼以前,
咱們須要在項目中安裝 chai, 以下命令:
npm install --save-dev chai
1)var expect = require('chai').expect;
即引用 chai 斷言庫,使用的是 expect斷言風格。
expect 官網API(http://chaijs.com/api/bdd/).
2)mocha測試代碼如何運行?
上面的add.test.js 編寫完成後,咱們須要運行測試代碼了,進入add.test.js代碼的目錄後,執行以下命令可運行:
mocha add.test.js
mocha命令後面也能夠指定多個文件,以下命令:
mocha xx.test.js yy.test.js
使用通配符:
或者咱們能夠運行以下命令,執行多個測試腳本文件:
mocha spec/{add,reduce}.js //目錄spec下的add.js和reduce.js文件
mocha spec/*.js //全部文件
mocha默認運行test子目錄裏面的測試腳本,咱們通常狀況下,能夠把測試腳本放在test目錄下,而後進入test的上層目錄,直接執行mocha命令便可:
mocha
而後你就會發現test目錄下第一層的因此測試文件都被運行了。命令只會執行test第一層目錄下全部文件,並不能執行嵌套目錄下的文件。
爲了執行全部嵌套目錄下的文件,咱們能夠 mocha命令後面加一個參數 --recursive 參數
更多的細節信息能夠看:https://www.cnblogs.com/tugenhua0707/p/8419534.html,固然以後你要補充一下
3)測試用例的鉤子
Mocha在describe塊之中,提供了測試用例的四個鉤子,before(), after(), beforeEach()和afterEach(),他們會在指定的時間內執行。
before(): 將會在全部測試用例執行以前運行,好比在以前插入數據等等操做。
after(): 會在全部測試執行以後運行,用於清理測試環境,回滾到清空數據狀態。
beforeEach(): 將會在每一個測試用例執行以前執行,可用於測試測試須要準備相關數據的條件。
afterEach(): 將會在每一個測試用例以後執行,可用於準備測試用例所需的後置條件。
4)理解異步鉤子函數
例子1:
var expect = require('chai').expect;
describe('異步鉤子函數', function() {
var foo = false;
beforeEach(function(){
setTimeout(function(){
foo = true;
}, 50)
});
it('異步鉤子函數成功', function() {
expect(foo).to.be.equal(true);
})
});
結果:
異步鉤子函數
異步鉤子函數成功:
AssertionError: expected false to equal true
+ expected - actual
-false
+true
如上能夠看到測試失敗,緣由是由於setTimeout 是異步的,在setTimeout執行完以前,it函數已經被執行了,因此foo當時數據仍是false,
所以false不等於true了。
這時候 done參數出來了,在回調函數存在時候,它會告訴mocha,你正在編寫一個異步測試,會等到異步測試完成的時候來調用done函數,或者超過2秒後超時,以下代碼就能夠成功了;
var expect = require('chai').expect;
describe('異步鉤子函數', function() {
var foo = false;
beforeEach(function(done){
setTimeout(function(){
foo = true;
// complete the async beforeEach
done();
}, 50)
});
it('異步鉤子函數成功', function() {
expect(foo).to.be.equal(true);
});
});
(3)這篇文章不是要很詳細地告訴你們概念性的內容,只是讓有跟我同樣想法(即學習了truffle框架後,發現裏面的那個測試十分有意思,想以後作測試的時候也用這種測試方法),可是忽然不知道怎麼入手的人一個方向,知道那是個什麼測試框架,以及去哪裏學習,以及一些比較簡單的必須知道的概念和內容,知道這些其實你就能夠寫一個十分簡單的測試例子了,建議結合別人的測試代碼進行學習,如https://github.com/larvalabs/cryptopunks/tree/master/test
在下面進行測試:
1)一開始,當我想要直接複製truffle中寫好的測試文件,進行小部分更改直接進行使用時,發現出錯:
truffle中只須要這兩句話就能夠部署好合約,可是在沒框架的狀況下是不能夠的
var testToken = artifacts.require(「./test-punk.sol」);
instance = await testToken.deployed(50);
這樣會報錯:
1.ReferenceError: artifacts is not defined
2.(function (exports, require, module, __filename, __dirname) { pragma solidity ^0.4.20;
^^^^^^^^
SyntaxError: Unexpected identifier
因此這就說明了在框架外是不能夠這樣子進行合約的編譯的
經過上面咱們就可以知道truffle到使用上面兩句部署指令前,還進行了編譯compile和部署migrate,因此在測試前要將合約的編譯和部署都弄好,你能夠經過查看我寫的remix的使用來學怎麼使用remix進行編譯和部署或者是看nodejs部署智能合約的方法來本身編寫代碼進行編譯和部署,最終獲得合約的部署地址NFMAddress
部署成功後,以後若是想在別的地方進行使用,須要如下幾句話句話:
const NFMAbi = require("./testToken.json");//合約生成的Abi,通常爲json文件
const NFMContract = web3.eth.contract(NFMAbi);
const instance = NFMContract.at(NFMAddress);
此時就可以調用該函數中的函數及變量了
2)其次,還要記得將相應的模塊包下載下來,這裏要添加package.json文件配置等內容
Error: Cannot find module ‘web3'
你安裝的web3必定要放在本地的node_modules文件夾下,否則是讀不出來的
3)使用nodejs來進行合約的編譯和部署時,發現出現下面的錯誤
1.let abi = compiledContract.contracts['testToken'].interface;
出錯:
TypeError: Cannot read property 'interface' of undefined
而後輸出compiledContract進行查看
2.console.log(compiledContract);
發如今編譯處就出錯了
{ contracts: {},
errors:
[ ':49:17: ParserError: Expected identifier, got \'LParen\'\n constructor (uint number) public{\n ^\n' ],
sourceList: [ '' ],
sources: {} }
還有:
{ contracts: {},
errors:
[ ':26:9: TypeError: Wrong argument count for function call: 2 arguments given but expected 1.\n require(propertyValueToOwner[propertyValue] == 0x0,\'this is not the first-sell\');\n ^------------------------------------------------------------------------------^\n',
發現多是版本的問題,由於這裏聲明構造函數使用了新的聲明方式,可是在這裏沒能被識別出。因此下載了新版本的solc,而後就成功了
4)
contract('testToken',async (accounts) => {
出錯:ReferenceError: contract is not defined
由於contract是truffle框架弄的,不在框架中是不可以這樣使用的,這時候想要使用帳號只能老實地鏈接區塊鏈,經過web3模塊去調用API接口
var Web3 = require("web3");
web3.setProvider(new Web3.providers.HttpProvider("http://localhost:8201"));
account1 = web3.eth.accounts[0];
5)最後運行結果也有問題:
用戶deMBP:testToken 用戶$ mocha test-mocha.js
testToken Test
check tokenNumber
1) deploy contract
2) sell token
3) buy token
4) check the balance
5) withdrawl the balance
0 passing (118ms)
5 failing
1) testToken Test
deploy contract:
TypeError: Cannot read property 'call' of undefined
at Context.<anonymous> (test-mocha.js:56:43)
2) testToken Test
sell token:
TypeError: Cannot read property 'sellToken' of undefined
at Context.<anonymous> (test-mocha.js:77:19)
3) testToken Test
buy token:
TypeError: Cannot read property 'testTokenIdToOwner' of undefined
at Context.<anonymous> (test-mocha.js:90:25)
4) testToken Test
check the balance:
TypeError: Cannot read property 'pendingDrawalOfUser' of undefined
at Context.<anonymous> (test-mocha.js:112:38)
5) testToken Test
withdrawl the balance:
TypeError: Cannot read property 'pendingDrawalOfUser' of undefined
at Context.<anonymous> (test-mocha.js:124:31)
Contract mined! address: 0x3cb4464f73eda60ac3ba1d46cd0544cd7ae18040 transactionHash: 0x62f27e3ccdfcb6ba54547107bbc8f1f9f152f0f588eddec9b1dc3a65d1d7d047
後面發現這個緣由是部署回調獲得instance前,it函數中的內容就已經開始調用了,這樣的話怎麼着instance都是undefined的,那麼確定是不可能可以調用合約中的函數的。並且在這裏將部署函數放在了一個單獨的it測試用例當中,可是下面的測試用例都是應該等待部署完成後纔可以測試成功的,那麼這樣就不可能成功測試了,由於it測試用例是同步進行的,在部署的同時,其餘測試用例也都開始運行了,⚠️有先後關係的測試內容應該要寫在一個測試用例當中。
因此就不作在這以前進行部署的事情了,畢竟咱們確定在測試以前是已經把合約部署上去的了,那麼只要用
let instance = MyContract.at('0x86757c9bdea10815e7d75a1577b6d9d2825dae0a');
這句話就好了
6)而後再運行也出錯:
mocha Error: Timeout of 2000ms exceeded.
則須要你再運行的時候添加
mocha -t 20000 test.js
由於其默認的時間是2000ms,你的時間若是過大,能夠進行本身設置
7)當你使用describe這些mocha的形式語句的時候,使用node test.js是不能運行成功的,會返回錯誤:
用戶MBP:testToken 用戶$ node test.js
/Users/用戶/testToken/test.js:165
describe('testToken',function(){
^
ReferenceError: describe is not defined
因此必定要用mocha開頭,mocha test.js
實現:
const debug = require("debug")("testToken"); const assert = require('assert') // var testToken = require("./test-punk.sol"); const Web3 = require('web3'); const web3 = new Web3(); web3.setProvider(new Web3.providers.HttpProvider('http://127.0.0.1:7545')); const fs = require("fs"); const solc = require("solc"); let source = fs.readFileSync("testToken.sol",'utf8');//read file let compiledContract = solc.compile(source,1);//compile // console.log(compiledContract); for (let contractName in compiledContract.contracts) { console.log("in"); var bytecode = compiledContract.contracts[contractName].bytecode; var abi = JSON.parse(compiledContract.contracts[contractName].interface); //將abi寫成json形式 console.log("out"); } // 你要測試的是接口 // console.log(bytecode); // console.log(abi); let gasEstimate = web3.eth.estimateGas({data:'0x'+bytecode}); let MyContract = web3.eth.contract(abi); debug("deploying contract"); // let instance; let instance = MyContract.at('0x86757c9bdea10815e7d75a1577b6d9d2825dae0a');//可改 var user1 = web3.eth.accounts[0]; console.log(user1); var user2 = web3.eth.accounts[1]; var user3 = web3.eth.accounts[2]; var user4 = web3.eth.accounts[3]; var user5 = web3.eth.accounts[4]; var propertyValues = ['0x00000001','0x00000002','0x00000003','0x00000004','0x00000005']; var prices = [11,12,13,14,15]; var users = [user1,user2,user3,user4,user5]; //這個地方是想要在這裏同時部署合約,可是發現老是不成功,部署異步老是太慢,before()函數好像也沒有什麼用,因此後面我也只能放棄部署了,只能先部署完獲得地址再來調用了 // function deployContract() { // instance = MyContract.new(50,{from:user1,data:'0x'+bytecode,gas:47000000},function(e,contract){ // if(typeof contract.address !== 'undefined'){ // console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); // } // }); // } // before(deployContract); // var instance; describe("testToken Test",function(){ // it("deploy contract",async function(){ it("contract begin",async function(){ let num = propertyValues.length; // instance = await testToken.deployed(50); console.log(instance.address); console.log('check tokenNumber'); console.log(await instance.tokenNumber.call()); debug("create token");
//首先先建立5個token for(let i=0; i<num; i++){ await instance.create(propertyValues[i],prices[i],{from:users[i],value:prices[i],gas:30000000}); } debug("display token");
//而後查看生成的token的屬性 let nextTokenId = await instance.nextTokenToCreate.call(); console.log("nextTokenId is :"+ nextTokenId); if(parseInt(nextTokenId) != 5){ console.log("initial token failed"); }else{ for(let i =0; i<num; i++){ console.log(await instance.propertyOfToken.call(i)); } } }); //而後sell token it("sell token",async function(){ await instance.sellToken(0,21,{from:user1,gas:30000000}); await instance.sellToken(1,22,{from:user2,gas:30000000}); //查看是否成功sell console.log(await instance.tokenIdToSell.call(0)); console.log(await instance.tokenIdToSell.call(1)); }); //其餘用戶對sell的token進行購買 it("buy token",async function(){
//查看購買前token的擁有者是誰 console.log(instance.testTokenIdToOwner.call(0)); console.log(instance.testTokenIdToOwner.call(1)); await instance.buyToken(0,{from:user3,value:21,gas:30000000}); await instance.buyToken(1,{from:user4,value:22,gas:30000000}); let buyer1 = await instance.testTokenIdToOwner.call(0); let buyer2 = await instance.testTokenIdToOwner.call(1); //查看購買後的擁有者是誰來覈實購買成功進行 console.log(buyer1); console.log(buyer2); console.log("check the sell after buying"); console.log(await instance.tokenIdToSell.call(0)); console.log(await instance.tokenIdToSell.call(1)); assert.equal(buyer1,user3,"buying 0 is failed"); assert.equal(buyer2,user4,"buying 1 is failed"); }); //查看用戶臨時帳戶中此時有多少積蓄 it("check the balance",async function(){ let user1Balance = await instance.pendingDrawalOfUser.call(user1); let user2Balance = await instance.pendingDrawalOfUser.call(user2); console.log(user1Balance); console.log(user2Balance); assert.equal(user1Balance,21,"user1 balance number is not right"); assert.equal(user2Balance,22,"user1 balance number is not right"); }); //而後將臨時帳戶中的錢轉到錢包中 it("withdrawl the balance",async function(){ console.log(await instance.pendingDrawalOfUser.call(user1)); console.log(await instance.pendingDrawalOfUser.call(user2)); await instance.withdrawl({from:user1,gas:30000000}); await instance.withdrawl({from:user2,gas:30000000}); console.log(await instance.pendingDrawalOfUser.call(user1)); console.log(await instance.pendingDrawalOfUser.call(user2)); }); }); 結果是: 用戶deMBP:testToken 用戶$ mocha test-mocha.js in out 0x3455f15cc11f2e77c055f931a6c918ccc7c18fd8 testToken Test 0x86757c9bdea10815e7d75a1577b6d9d2825dae0a check tokenNumber BigNumber { s: 1, e: 1, c: [ 50 ] } nextTokenId is :5
//生成的token的屬性 [ BigNumber { s: 1, e: 0, c: [ 0 ] }, '0x0000000100000000000000000000000000000000000000000000000000000000', '0x3455f15cc11f2e77c055f931a6c918ccc7c18fd8', BigNumber { s: 1, e: 1, c: [ 11 ] } ] [ BigNumber { s: 1, e: 0, c: [ 1 ] }, '0x0000000200000000000000000000000000000000000000000000000000000000', '0x7ddad6a67544efb0c51808c77009a7b98cc81630', BigNumber { s: 1, e: 1, c: [ 12 ] } ] [ BigNumber { s: 1, e: 0, c: [ 2 ] }, '0x0000000300000000000000000000000000000000000000000000000000000000', '0xe9478ebcf4c755ad945a351261c8fa046672963b', BigNumber { s: 1, e: 1, c: [ 13 ] } ] [ BigNumber { s: 1, e: 0, c: [ 3 ] }, '0x0000000400000000000000000000000000000000000000000000000000000000', '0x920f422b761976972a9eadbec1f5341a9747ea6a', BigNumber { s: 1, e: 1, c: [ 14 ] } ] [ BigNumber { s: 1, e: 0, c: [ 4 ] }, '0x0000000500000000000000000000000000000000000000000000000000000000', '0xa17a7fa74a7dd57dff005b45234292e7daaf150c', BigNumber { s: 1, e: 1, c: [ 15 ] } ] ✓ contract begin (1541ms)
// [ true, '0x0000000100000000000000000000000000000000000000000000000000000000', BigNumber { s: 1, e: 0, c: [ 0 ] }, '0x3455f15cc11f2e77c055f931a6c918ccc7c18fd8', BigNumber { s: 1, e: 1, c: [ 21 ] } ] [ true, '0x0000000200000000000000000000000000000000000000000000000000000000', BigNumber { s: 1, e: 0, c: [ 1 ] }, '0x7ddad6a67544efb0c51808c77009a7b98cc81630', BigNumber { s: 1, e: 1, c: [ 22 ] } ] ✓ sell token (663ms) 0x3455f15cc11f2e77c055f931a6c918ccc7c18fd8 0x7ddad6a67544efb0c51808c77009a7b98cc81630 0xe9478ebcf4c755ad945a351261c8fa046672963b 0x920f422b761976972a9eadbec1f5341a9747ea6a check the sell after buying [ false, '0x0000000100000000000000000000000000000000000000000000000000000000', BigNumber { s: 1, e: 0, c: [ 0 ] }, '0x0000000000000000000000000000000000000000', BigNumber { s: 1, e: 0, c: [ 0 ] } ] [ false, '0x0000000200000000000000000000000000000000000000000000000000000000', BigNumber { s: 1, e: 0, c: [ 1 ] }, '0x0000000000000000000000000000000000000000', BigNumber { s: 1, e: 0, c: [ 0 ] } ] ✓ buy token (954ms) BigNumber { s: 1, e: 1, c: [ 21 ] } BigNumber { s: 1, e: 1, c: [ 22 ] } ✓ check the balance (206ms) BigNumber { s: 1, e: 1, c: [ 21 ] } BigNumber { s: 1, e: 1, c: [ 22 ] } BigNumber { s: 1, e: 0, c: [ 0 ] } BigNumber { s: 1, e: 0, c: [ 0 ] } ✓ withdrawl the balance (631ms) 5 passing (4s)
注意:在這裏看好像這個例子也可以順序執行,可是後面發現上面例子的因此it應該合成一個it來寫,否則順序是不必定能保證的,由於it測試用例在運行時是同步運行的,可是我這裏的測試用例實際上是有但願它按照順序來運行,因此改成:
describe("testToken Test",function(){ it("contract begin",async function(){ let num = propertyValues.length; // instance = await testToken.deployed(50); console.log(instance.address); console.log('check tokenNumber'); console.log(await instance.tokenNumber.call()); debug("create token"); //首先先建立5個token for(let i=0; i<num; i++){ await instance.create(propertyValues[i],prices[i],{from:users[i],value:prices[i],gas:30000000}); } debug("display token"); //而後查看生成的token的屬性 let nextTokenId = await instance.nextTokenToCreate.call(); console.log("nextTokenId is :"+ nextTokenId); if(parseInt(nextTokenId) != 5){ console.log("initial token failed"); }else{ for(let i =0; i<num; i++){ console.log(await instance.propertyOfToken.call(i)); } } //而後sell token await instance.sellToken(0,21,{from:user1,gas:30000000}); await instance.sellToken(1,22,{from:user2,gas:30000000}); //查看是否成功sell console.log(await instance.tokenIdToSell.call(0)); console.log(await instance.tokenIdToSell.call(1)); //其餘用戶對sell的token進行購買 //查看購買前token的擁有者是誰 console.log(instance.testTokenIdToOwner.call(0)); console.log(instance.testTokenIdToOwner.call(1)); await instance.buyToken(0,{from:user3,value:21,gas:30000000}); await instance.buyToken(1,{from:user4,value:22,gas:30000000}); let buyer1 = await instance.testTokenIdToOwner.call(0); let buyer2 = await instance.testTokenIdToOwner.call(1); //查看購買後的擁有者是誰來覈實購買成功進行 console.log(buyer1); console.log(buyer2); console.log("check the sell after buying"); console.log(await instance.tokenIdToSell.call(0)); console.log(await instance.tokenIdToSell.call(1)); assert.equal(buyer1,user3,"buying 0 is failed"); assert.equal(buyer2,user4,"buying 1 is failed"); //查看用戶臨時帳戶中此時有多少積蓄 let user1Balance = await instance.pendingDrawalOfUser.call(user1); let user2Balance = await instance.pendingDrawalOfUser.call(user2); console.log(user1Balance); console.log(user2Balance); assert.equal(user1Balance,21,"user1 balance number is not right"); assert.equal(user2Balance,22,"user1 balance number is not right"); //而後將臨時帳戶中的錢轉到錢包中 console.log(await instance.pendingDrawalOfUser.call(user1)); console.log(await instance.pendingDrawalOfUser.call(user2)); await instance.withdrawl({from:user1,gas:30000000}); await instance.withdrawl({from:user2,gas:30000000}); console.log(await instance.pendingDrawalOfUser.call(user1)); console.log(await instance.pendingDrawalOfUser.call(user2)); }); });