Unit Testing in Truffle

const People = artifacts.require(“People”);
const truffleAssert = require(“truffle-assertions”);

contract(“People”, async function(accounts){
it(“shouldn’t be possible to delete a person without being the contract owner”, async function(){
let instance = await People.deployed();
await instance.createPerson(“Dell”, 30, 210, {value: web3.utils.toWei(“1”,“ether”), from: accounts[2]});
await truffleAssert.fails(instance.deletePerson(accounts[2], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
});
it(“should be possible to delete a persen by the contract owner”, async function(){
let instance = await People.deployed();
//await instance.createPerson(“Dell”, 30, 210, {value: web3.utils.toWei(“1”,“ether”), from: accounts[2]});
await instance.deletePerson(accounts[2], {from: accounts[0]});
const {0: Name, 1: Age, 2: Height, 3: Senior} = await instance.getPerson({from: accounts[2]});
assert(Name === “” && Age == 0, “Person not deleted”);
});
});

Hey dani,

thx for the reply. The code I use should be the one from the course:

modifier costs(uint cost){
        require(msg.value >= cost);
        _;
    }

function createPerson(string memory name, uint age, uint height) public payable costs(1 ether){
      require(age < 150, "Age needs to be below 150");
      balance += msg.value;

        //This creates a person
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;

        if(age >= 65){
           newPerson.senior = true;
       }
       else{
           newPerson.senior = false;
       }

        insertPerson(newPerson);
        creators.push(msg.sender);

        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name,
                    people[msg.sender].age,
                    people[msg.sender].height,
                    people[msg.sender].senior
                )
            )
            ==
            keccak256(
                abi.encodePacked(
                    newPerson.name,
                    newPerson.age,
                    newPerson.height,
                    newPerson.senior
                )
            )
        );
        emit personCreated(newPerson.name, newPerson.senior);
    }

I still didnt figure out the problem. My current guess is that sth is wrong with my javascript code…
I have created the following minimal test:

const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");

contract("People", async function(accounts){

  let instance;

  before(async function(){
    instance = await People.deployed();
  });

  it("souldnt create if not payed appropriately (-1Wei)", async function(){
    await truffleAssert.fails(instance.createPerson("Bob",60,180,{value:(10**18-1)}),truffleAssert.ErrorType.REVERT);
  });

  it("souldnt create if not payed appropriately (-10Wei)", async function(){
    await truffleAssert.fails(instance.createPerson("Bob",60,180,{value:(10**18-10)}),truffleAssert.ErrorType.REVERT);
  });

  it("souldnt create if not payed appropriately (-100Wei)", async function(){
    await truffleAssert.fails(instance.createPerson("Bob",60,180,{value:(10**18-100)}),truffleAssert.ErrorType.REVERT);
  });
});

As mentioned in my earlier post the first and second call create a Person though they shouldnt.

Thx already for your ideas!

Edit: just after writing this reply I may have found the solution myself. Apparently JS is rounding large numbers (i guess i would have known that if i had taken the JS course first…). I found the following BlogPost which explains it:

1 Like

Your answer is correct.
This is what we get if we try to console.log:

10**18-1
10**18-10
10**18-100

Schermata 2020-09-02 alle 12.09.13

Kudos for having found the solution yourself.

1 Like

Here is my solution:

it("should delete the person ", async function(){
    let instance = await People.deployed();
    await instance.createPerson("Bob", 65, 190, {from: accounts[3], value: web3.utils.toWei("1", "ether")});
    await assert(instance.deletePerson(accounts[0], { from: accounts[0]}));
  });

Can you please check what am I doing wrong in the code below:

it("should have equal number between balance variable and the balance of the contract", async function(){
    let instance = await People.new();
    console.log(await web3.eth.getBalance("0x4f8eE19Da2ff65FC99e4f8BFCDDFB4cEDB6B8734"));
    await instance.createPerson("Ros", 25, 172, {from: accounts[1], value: web3.utils.toWei("3", "ether")});
    let bal = await instance.balanace;
    assert(bal === await (web3.eth.getBalance("0x4f8eE19Da2ff65FC99e4f8BFCDDFB4cEDB6B8734"))
    , "Balance of the contract is not equal" );
    console.log(await web3.eth.getBalance("0x4f8eE19Da2ff65FC99e4f8BFCDDFB4cEDB6B8734"));
  });

I could have not used theOwner and nonOwner but i understand it better this way.

  it("delete can not be performed by nonOwner", async function(){
    let instance = await People.deployed();
    let nonOwner = accounts[1];
    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
    await truffleAssert.fails(instance.deletePerson(nonOwner, {from: nonOwner}), truffleAssert.ErrorType.REVERT);
  });
  it("delete can be performed by theOwner", async function(){
    let instance = await People.deployed();
    let theOwner = accounts[0];
    let nonOwner = accounts[1];
    await instance.createPerson("Hank", 45, 183, {from: nonOwner, value: web3.utils.toWei("1", "ether")});
    await truffleAssert.passes(instance.deletePerson(nonOwner, {from: theOwner}), truffleAssert.ErrorType.REVERT);
  });

Hey @rostyslavdzhohola

Check here:

it("should have equal number between balance variable and the balance of the contract", async function(){
    let instance = await People.new();
    console.log(await web3.eth.getBalance(instance.address));
    await instance.createPerson({from: accounts[1], value: web3.utils.toWei("3", "ether")});
    let bal =  await web3.eth.getBalance(instance.address);
    assert(bal == 3 * 10**18);
    console.log(await web3.eth.getBalance(instance.address));
  });

I have replaced your contract address with instance.address.

let bal =  await web3.eth.getBalance(instance.address);
    assert(bal == 3 * 10**18);

After depositing 3 ether by calling createPerson() we do once again check the contract balance and we assign the result to bal.
Then we assert that bal is equal to 3 eth (3 * 10**18);

Happy learning,
Dani

1 Like

Thanks for the correction.
Question about assert function. I see that you have used only 2 equal signs and 2 multiplication signs. Can you explain why there are not 3 equal sings and 1 multiplication sign?

Here are all my tests for value assignment:

it("should have equal number between balance variable and the balance of the contract", async function(){
    let instance1 = await People.new();
    console.log(await web3.eth.getBalance(instance1.address));
    await instance1.createPerson("Ros", 25, 172, {from: accounts[1], value: web3.utils.toWei("3", "ether")});
    let bal = await web3.eth.getBalance(instance1.address);
    assert((bal == 3* 10**18)
    , "Balance of the contract is not equal to 3" );
    console.log(await web3.eth.getBalance(instance1.address));
  });
  it("should withdraw all ", async function(){
    let instance1 = await People.new();
    await instance1.createPerson("Ros", 25, 172, {from: accounts[5], value: web3.utils.toWei("3", "ether")});
    await truffleAssert.passes(instance1.withdrawAll(), "This method should pass");
    let bal = await web3.eth.getBalance(instance1.address);
    assert(bal == 0, "Balanace is not 0");
    console.log(await web3.eth.getBalance(instance1.address));
  });
  it("should fail to withdraw all ", async function(){
    await instance.createPerson("Ros", 25, 172, {from: accounts[5], value: web3.utils.toWei("3", "ether")});
    await truffleAssert.fails(instance.withdrawAll({from: accounts[5]}), truffleAssert.ErrorType.REVERT);
  });

Special thanks to @ dani69654 for helping with the first test.

@rostyslavdzhohola

I see that you have used only 2 equal signs

The difference between “==” and “===” operator is that == compares variable by making type correction.
=== doesn’t allow that.
Schermata 2020-09-04 alle 16.15.15

In your case you could also have used === but is common practice to compare two numbers with ==.

2 multiplication signs

** means at the power of.

Example:
2 at the power of 3.
Schermata 2020-09-04 alle 16.18.26

So what I wrote here:

3 * (10**18).

Now 10 ** 18 = 1 ether (1000000000000000000 wei).

3 * 1 ether = 3 ether.

Cheers,
Dani

2 Likes
it("should allow the owner to delete people", async function(){
    let instance = await People.deployed();
    await truffleAssert.passes(
      instance.deletePerson(
        accounts[1],
        {from: accounts[0]}),
        truffleAssert.ErrorType.REVERT);
  });
1 Like
  it("should add balance correctly after createPerson call with 1 ether", async function(){
    let instance = await People.new();
    await instance.createPerson("Lisa", 35, 160,
    {from: accounts[2],
      value: web3.utils.toWei("1", "ether")});

    let balance = await instance.balance();
    let floatBalance = parseFloat(balance);

    let realBalance = await web3.eth.getBalance(instance.address);

    assert(floatBalance == web3.utils.toWei("1", "ether") && floatBalance == realBalance)
  });
  it("should allow the owner to withdraw balance", async function(){
    let instance = await People.new();
    await instance.createPerson("Lisa", 35, 160,
     {from: accounts[2],
        value: web3.utils.toWei("1", "ether")});

    await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));
  });
  it("should not allow a non-owner to withdraw balance", async function(){
    let instance = await People.new();
    await instance.createPerson("Lisa", 35, 160,
     {from: accounts[2],
        value: web3.utils.toWei("1", "ether")});

    await truffleAssert.fails(instance.withdrawAll({from: accounts[2]}),
     truffleAssert.ErrorType.REVERT);
  });
  it("owners balance should increase after withdrawal", async function(){
    let instance = await People.new();
    await instance.createPerson("Lisa", 35, 160,
     {from: accounts[2],
        value: web3.utils.toWei("1", "ether")});

    let balanceBefore = parseFloat(await web3.eth.getBalance(accounts[0]));
    await instance.withdrawAll();
    let balanceAfter = parseFloat(await web3.eth.getBalance(accounts[0]));
    assert(balanceBefore < balanceAfter, "Owners balance was not increased after withdrawal");

  });
  it("should reset balance to 0 after withdrawal", async function(){
    let instance = await People.new();
    await instance.createPerson("Lisa", 35, 160,
     {from: accounts[2],
        value: web3.utils.toWei("1", "ether")});

    await instance.withdrawAll();

    let balance = await instance.balance();
    let floatBalance = parseFloat(balance);

    let realBalance = await web3.eth.getBalance(instance.address);

    assert(floatBalance == web3.utils.toWei("0", "ether") && floatBalance == realBalance,
     "Contract balance was not 0 after withdrawal or did not match")

  })
1 Like
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
const AssertionError = require("assertion-error");

contract("People", accounts => {
   let instance;

   before(async function(){
      instance = await People.deployed()
   });

   const owner = accounts[0];
   const hacker = accounts[1];

   it("User can't delete a person", async () => {
      await instance.createPerson("Bob", 20, 190, {value: web3.utils.toWei("1", "ether"), from: hacker});
      await truffleAssert.fails(instance.deletePerson(hacker, {from: hacker}), truffleAssert.ErrorType.REVERT, null, "User can't delete person");
   });
   
   it("Owner can delete a person", async () => {
      await instance.createPerson("Bob", 20, 190, {value: web3.utils.toWei("1", "ether"), from: hacker});
      await truffleAssert.passes(instance.deletePerson(hacker, {from: owner}), null, "Owner was not able to delete person!");

   });
});
1 Like
  it("should fail if non owner tries to delete a person", async () => {
      const instance = await People.deployed();
      await instance.createPerson("Bob", 20, 190, {value: web3.utils.toWei("1", "ether"), from: accounts[1]})
      await truffleAssert.fails(instance.deletePerson(accounts[1],
              {from: accounts[1] }), truffleAssert.ErrorType.REVERT);
  });

  it("should allow the owner to delete a person", async () => {
      const instance = await People.deployed();
      await instance.createPerson("Max", 22, 180, {value: web3.utils.toWei("1", "ether"), from: accounts[2]})
      await truffleAssert.passes(instance.deletePerson(accounts[2], {from: accounts[0] }));
  });

@Taha
I am not sure i understand well :
{from: accounts[0] }
{from: accounts[1] }
{from: accounts[2] }
I get confused when we do things like:
await instance.createPerson(“Lisa”, 35, 160, {from: accounts[2], value: web3.utils.toWei(“1”, “ether”)});
Does this mean we are taking 1 eth from that other account? And would the owner of this be accounts[0]?
Do you have a link that I could read and understand this better?

it("should increase balance after createPerson", async function(){
        const instance = await People.new();
        await instance.createPerson("Marc", 37, 188, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
        const balance = await instance.balance();
        const instanceBalance = parseFloat(balance);
        const realBalance = await web3.eth.getBalance(instance.address);

        assert(instanceBalance == web3.utils.toWei("1", "ether") && instanceBalance == realBalance)
    });
    
    it("should allow the owner to withdraw balance", async () => {
        let instance = await People.new();
        await instance.createPerson("Marc", 37, 188, {from: accounts[2], value: web3.utils.toWei("1", "ether")});

        await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));
    });

    it("owners balance should increase after withdrawal", async () => {
        const instance = await People.new();
        await instance.createPerson("Marc", 37, 188, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
        const realBalanceBefore = parseFloat(await web3.eth.getBalance(accounts[0]));
        await instance.withdrawAll();
        const realBalanceAfter = parseFloat(await web3.eth.getBalance(accounts[0]));

        assert(realBalanceBefore < realBalanceAfter, "Owners balance was not increased");
    });

    it("should reset balance after withdrawal", async () => {
        const instance = await People.new();
        await instance.createPerson("Marc", 37, 188, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
        await instance.withdrawAll();
        const balance = await instance.balance();
        const instanceBalance = parseFloat(balance);
        const realBalance = await web3.eth.getBalance(instance.address);

        assert(instanceBalance == web3.utils.toWei("0", "ether") && instanceBalance == realBalance, "Reset balance failed")
    })
/*
Value Assignment
1) When a person is added the balance of the contract is increased and match the balance address of the contract
2) The contract Owner can withdraw that balance and the balance became zero in the balance storage 
  and in the contract address balance, and that the owner balance is increased
*/


const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
const AssertionError = require("assertion-error");

async function getBalance(_instance) {
  let balance = await _instance.balance()
  //console.log("getBalance TEST: ", parseFloat(balance))
  return parseFloat(balance)
}

contract("People", accounts => {
  let instance;
  let contractAddress;

  before(async function(){
     instance = await People.deployed()
     contractAddress = instance.address;
  });

  const owner = accounts[0];
  const user = accounts[1];
  //const contractAddress = instance.address;

  it("should increase the balance in both storage and contract address when a person is added", async () => {
     // Test that balance is increased
     const origBalance = await getBalance(instance)
     await instance.createPerson("Bob", 20, 190, {value: web3.utils.toWei("1", "ether"), from: user});
     const nowBalance = await getBalance(instance)

     assert(nowBalance > 0, "Balance increase error!");
     
     //console.log(`BALANCE: orig=${origBalance} now=${nowBalance}`);

     assert(origBalance < nowBalance, "Balance was not increased!");
     
     // Test that contract and storage address are the same
     let contractBalance = await web3.eth.getBalance(contractAddress);
     contractBalance = parseFloat(contractBalance);
     
     //console.log(`BALANCE: contract=${contractBalance} now=${nowBalance}`);

     assert(contractBalance === nowBalance, "storage balance and contract balance are not equal!");
  });

  it("Only owner can withdraw", async () => {
     await truffleAssert.fails(instance.withdrawAll({from: user}), truffleAssert.ErrorType.REVERT, null, "User can't withdraw");
     await truffleAssert.passes(instance.withdrawAll({from: owner}), truffleAssert.ErrorType.REVERT, null, "Owner was not able to withdraw");
  })

  it("when the owner withdraw the contract balance, both of storage and contract balance have to be 0, and owner balance increased" , async () => {
     instance = await People.new()
     const origOwnerBalance = await web3.eth.getBalance(owner)
     await instance.createPerson("Bob", 20, 190, {value: web3.utils.toWei("1", "ether"), from: user});
     await instance.withdrawAll()
     const nowOwnerBalance = await web3.eth.getBalance(owner)
     
     const storageBalance = await getBalance(instance)
     let contractBalance = await web3.eth.getBalance(contractAddress);
     contractBalance = parseFloat(contractBalance);

     assert(storageBalance === 0, "Storage balance is not 0!")
     assert(contractBalance === 0, "Contract balance is not 0!")

     //console.log(`BALANCE: orig=${origOwnerBalance} now=${nowOwnerBalance}`)
     assert(nowOwnerBalance > origOwnerBalance, "Owner balance was not increased!")
  })
  
  
});

By default the accounts[0] is the one that creates the contract so accounts[0] is the owner.
The owner of the contract People is the only one that can withdraw ether from the contract.
from: accounts[2]
means you are using the ether from the account[2] for creating a person.

1 Like

Just guessing:
Maybe because of this line in truffle-config.js ?

// from: <address>,        // Account to send txs from (default: accounts[0])
  it("should earn when person added", async function(){
    let before = parseInt(await web3.eth.getBalance(People.address));
    let increase = parseInt(web3.utils.toWei("1", "ether"));
    let expect = before + increase;
    // when
    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
    // then
    let afterOnChain = parseInt(await web3.eth.getBalance(People.address));
    let afterContract = parseInt( await instance.balance.call() );
    assert(afterOnChain === expect, "Expect increased balance, was: " + afterOnChain);
    assert(afterOnChain === afterContract, "Expect same balance, was: " + afterContract);
  })
  it("should allow owner to withdraw all", async function(){
    let owner = accounts[0];
    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
    let before = parseInt(await web3.eth.getBalance(People.address));
    let expect = 0;
    // when
    await truffleAssert.passes(instance.withdrawAll({from: owner}));
    // then
    let afterOnChain = parseInt(await web3.eth.getBalance(People.address));
    let afterContract = parseInt( await instance.balance.call() );
    assert(afterOnChain === expect, "Expect increased balance, was: " + afterOnChain);
    assert(afterOnChain === afterContract, "Expect same balance, was: " + afterContract);
  })