Unit Testing in Truffle

Balance / Value testing


// requirement: truffle-assertions
// install: npm install truffle-assertions
// usage: const truffleAssert = require('truffle-assertions');

// Tests:
// Check contract handles values correctly
// - When createPerson(), balance increases and increases correctly
// - Must match the new correct balance of the contract address on the blockchain
// - Check the owner can withdraw the balance
// - Check the balance is reduced to 0
// - Check the owner wallet address is updated correctly on the blockchain

// Helpers
// web3.eth.getBalance(address)
// get the contract address from instance.address

// Functions tested:
// function createPerson(string memory name, uint age, uint height) public payable costs(1 ether)
// function withdrawAll() public onlyOwner returns(uint) {

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

contract("People", async function(accounts) {
    let instance;
    let contractPreBalance;
    let contractPostBalance;
    let ownerPreWithdrawl;
    let ownerPostWithdrawl;
    
    // before() runs once before anythign else
    before(async function() {
        instance = await People.deployed();
    });

    it("Check contract balances are increased correctly when creating a person.", async function() {
        contractPreBalance = await web3.eth.getBalance(instance.address);
        //console.log(" > > Balance pre creation: " + contractPreBalance);
        
        await instance.createPerson("Person 1", 35, 170, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
        contractPostBalance = await web3.eth.getBalance(instance.address);
        //console.log(" > > Balance post creation: " + contractPostBalance);

        await truffleAssert.passes(contractPostBalance === contractPreBalance + web3.utils.toWei("1", "ether"));
        await truffleAssert.passes(instance.balance === contractPostBalance);
    });
    it("Ensure non-owners cannot withdrawAll().", async function() {
        await truffleAssert.fails(instance.withdrawAll({from: accounts[1]}), truffleAssert.ErrorType.REVERT);
    });
    it("Check contract balance is zeroed and owner balance is increased correctly when withdrawing.", async function() {
        contractPreBalance = await web3.eth.getBalance(instance.address);
        ownerPreWithdrawl = await web3.eth.getBalance(accounts[0]);

        //console.log(" > > Contract balance pre creation: " + contractPreBalance);
        //console.log(" > > Owner balance pre creation: " + ownerPreWithdrawl);

        await instance.withdrawAll({from: accounts[0]});
        contractPostBalance = await web3.eth.getBalance(instance.address);
        ownerPostWithdrawl = await web3.eth.getBalance(accounts[0]);
        
        //console.log(" > > Contract balance post withdrawl: " + contractPostBalance);
        //console.log(" > > Owner balance post withdrawl: " + ownerPostWithdrawl);

        await truffleAssert.passes(contractPostBalance === 0);
        await truffleAssert.passes(ownerPostWithdrawl > ownerPreWithdrawl);
    });
});```
1 Like

Here is mine - freshly baked:

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

contract(“People”, async function(accounts) {
it(“should be able to delete a person as the contract owner”, async function() {
let instance = await People.deployed();
//Creating person as a non contract owner to simulate real world situation:
await instance.createPerson(“Mr. Test”, 30, 190, {value: web3.utils.toWei(“1”, “ether”), from: accounts[1]});
//Some debug stuff to see what is happening under the hood:
//person = await instance.getPerson();
//console.log(person);
//console.log(person[0]);

	//Delete as the contract owner:
	instance.deletePerson(accounts[1], {from: accounts[0]});
	person = await instance.getPerson();
	//console.log(person[0]);
	assert(person[0] === '', 'Deletion failed - person still exists');
});

it("shouldn't be able to delete a person if not the contract owner", async function() {
	let instance = await People.deployed();
	//Creating person as a non contract owner to simulate real world situation:
	await instance.createPerson("Mr. Test", 30, 190, {value: web3.utils.toWei("1", "ether"), from: accounts[1]});
	//Some debug stuff to see what is happening under the hood:
	//person = await instance.getPerson();
	//console.log(person);
	//console.log(person[0]);
	
	//Trying to delete person as a non contract owner - everything except accounts[0] should fail this:
	await truffleAssert.fails(
		instance.deletePerson(accounts[1], {from: accounts[1]}),
		truffleAssert.ErrorType.REVERT
	);
});

})

1 Like

Below is the error being thrown in terminal :point_down:
Contract: People
✓ should’nt create a Person over age 150 (162ms)
✓ Shouldn’t create a Person with age Zero (111ms)
✓ shouldn’t allow transactions below threshhold wei payable limits
✓ Should set all human mapping properties correctly (190ms)

  1. Shouldn’t allow non owner to delete Person

No events were emitted

  1. Should only allow owner to delete Person

No events were emitted

4 passing (531ms)
2 failing

  1. Contract: People
    Shouldn’t allow non owner to delete Person:
    ReferenceError: accounts is not defined
    at Context. (test/Peopletest.js:36:103)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  2. Contract: People
    Should only allow owner to delete Person:
    ReferenceError: accounts is not defined
    at Context. (test/Peopletest.js:41:54)
    at process._tickCallback (internal/process/next_tick.js:68:7)

2
truffle(ganache)> accounts[0]
‘0x687f17fe288c4AD8Fa4A918239DaA75b79062B75’
truffle(ganache)> accounts[1]
‘0xDF9E3247d15AA90Df22a594810C9F16Cc994A1C2’
truffle(ganache)> accounts[2]
‘0xd77F17e9b474a9Cca0eD13D3a47Eb97a0cB3B638’
truffle(ganache)>

Below is my Code :point_down:

it("Shouldn't allow non owner to delete Person", async function(){
    let instance = await People.deployed();
    await instance.createPerson(35, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether"), from : accounts[2]});
    await truffleAssert.fails(instance.deletePerson(accounts[2], {from : accounts[1]}), truffleAssert.ErrorType.REVERT);
  });
  it("Should only allow owner to delete Person", async function(){
    let instance = await People.deployed();
    await truffleAssert.passes(instance.deletePerson(accounts[1], {from : accounts[0]}));
  });



The main issue is that its saying that accounts is not defined , whereas we I am consoling accounts in the terminal, it identifies the accounts , which means ganache is working :point_down:
truffle(ganache)> accounts[0]

‘0x687f17fe288c4AD8Fa4A918239DaA75b79062B75’

truffle(ganache)> accounts[1]

‘0xDF9E3247d15AA90Df22a594810C9F16Cc994A1C2’

truffle(ganache)> accounts[2]

‘0xd77F17e9b474a9Cca0eD13D3a47Eb97a0cB3B638’

truffle(ganache)>
Can you please help in resolving the issue, as i am unable to understand ?

Thanks and Regards

Su.kal crypto

So hard my friends, I know this is only the peak of the iceberg, but I struggle and in the end I do it.
Keep push forward.

it("shouldn't a non-owner can withdrawAll contract balance", async function(){
    instance = await People.new();
    await instance.createPerson("Bob", 35, 190, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
    await truffleAssert.fails(instance.withdrawAll({from: accounts[1]}), truffleAssert.ErrorType.REVERT);
  });
  it("should owner can withdrawAll contract balance", async function(){
    instance = await People.new();
    await instance.createPerson("Bob", 35, 190, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
    await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));
  });
  it("should, after withdrawAll, balance's owner increase", async function(){
    instance = await People.new();
    await instance.createPerson("Bob", 35, 190, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
    let Owner_first = web3.eth.getBalance(accounts[0]);
    await instance.withdrawAll({from: accounts[0]});
    await truffleAssert.passes(Owner_first < web3.eth.getBalance(accounts[0]), "balance is not increased");

  });
  it("should, after withdrawAll, contractAddress be = 0 and owner balance be up", async function(){
    Contract_balance = web3.eth.getBalance(People.address);
    await truffleAssert.passes(Contract_balance == 0, "Contract balance should be 0");
  });
1 Like

Probably it isn’t perfect but it is mine, let’s go guyyyyyyys…

1 Like

Owner test assignment:
const People = artifacts.require(“People”);
const truffleAssert = require(“truffle-assertions”);

contract(“People”, async function(accounts){

it ("Shouldn't delete a person without being the owner",async function () {
    let instance = await People.deployed();
    await instance.createPerson("Bob", 66, 190, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
    await truffleAssert.fails(instance.deletePerson(accounts[0],{from: accounts[1]}), truffleAssert.ErrorType.REVERT);
});

it ("Should delete a person if request is made by owner",async function () {
    let instance = await People.deployed();
    await truffleAssert.passes(instance.deletePerson(accounts[1]) ,  truffleAssert.ErrorType.REVERT);
});     

});

1 Like

Have you added accounts as param of your contract?

You can refer to: https://academy.ivanontech.com/products/ethereum-smart-contract-programming-201/categories/1993911/posts/6668016

1 Like

HERE BELOW IS MY VALUE ASSIGNMENT :point_down:

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

contract("People", async function(accounts){
  let instance;
  //ownerAddress = accounts[0];


  beforeEach(async function(){
    instance = await People.new();

  });
  it("should'nt create a Person over age 150", async function(){

    await truffleAssert.fails(instance.createPerson(200, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
  });
  it("Shouldn't create a Person with age Zero", async function(){

    await truffleAssert.fails(instance.createPerson(0, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
  });
  it("shouldn't create Person without sufficient Payment", async function(){

    await truffleAssert.fails(instance.createPerson(50, "Bob", "Proctor", {value : 99}, truffleAssert.ErrorType.REVERT));
  });
  it("Should set all human mapping properties correctly", async function(){

    await instance.createPerson(65, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether")});
    let person = await instance.getPerson();
    assert(person.senior === true, person.age.toNumber() === 65, person.firstName === "Bob", person.lastName === "Proctor", "Mapping not set correctly");
  });
  it("Shouldn't allow non owner to delete Person", async function(){
    await instance.createPerson(39, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether"), from : accounts[1]});
    await truffleAssert.fails(instance.deletePerson(accounts[1], {from : accounts[1]}), truffleAssert.ErrorType.REVERT);
  });
  it("Should only allow owner to delete Person", async function(){

    await instance.createPerson(39, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether"), from : accounts[1]});
    await truffleAssert.passes(instance.deletePerson(accounts[1], {from : accounts[0]}));
  });
  it("Should allow owner to withdraw all and owner Balance should increase", async function(){

    let ownerOldBalance = parseFloat(await web3.eth.getBalance(accounts[0]));
    await instance.createPerson(39, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether"), from : accounts[1]});
    await instance.withdrawAll( {from : accounts[0]} );
    let ownerNewBalance = parseFloat(await web3.eth.getBalance(accounts[0]));
    assert(ownerNewBalance > ownerOldBalance, "Owners Balance has not increased after withdrawal");
    });
  it("Contract Balance must become 0 after withdrawal", async function(){

    await instance.createPerson(39, "Bob", "Proctor", {value : web3.utils.toWei("1", "ether"), from : accounts[2]});
    await instance.withdrawAll( {from : accounts[0]});
    let contractRealBalance = parseFloat(await web3.eth.getBalance(instance.address));
    let newBalance = await instance.balance();
    let floatBalance = parseFloat(newBalance);
    assert(floatBalance == web3.utils.toWei("0", "ether") && floatBalance === contractRealBalance, "Contract Balance has not become 0 after withdrawal");
    });

});
1 Like

Here is mine solution. Also… Merry Xmas everybody!

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


contract("People", async function(accounts) {
	
	let instance;
	beforeEach(async function(){
		instance = await People.deployed();
		await instance.createPerson("Mr. Test", 30, 190, {value: web3.utils.toWei("1", "ether"), from: accounts[1]});
	});
	
	it("should be able to pay funds to the contract", async function() {
		let balance = await web3.eth.getBalance(instance.address)
		//console.log('FFFFF ' + balance/1000000000000000000);
		assert(balance/1000000000000000000 === 1, 'Payment failed');
	});
	
 	it("should be able to withdraw all funds by owner", async function() {
		let instance = await People.deployed();
		await instance.createPerson("Mr. Test", 30, 190, {value: web3.utils.toWei("1", "ether"), from: accounts[1]});
		await instance.withdrawAll({from: accounts[0]});
		let balance = await web3.eth.getBalance(instance.address)
		assert(balance/1000000000000000000 === 0, 'Withdrawal failed');
	}); 
	
	it("shouldn't be able to withdraw all funds by non-owner", async function() {
		let instance = await People.deployed();
		await instance.createPerson("Mr. Test", 30, 190, {value: web3.utils.toWei("1", "ether"), from: accounts[1]});
		await truffleAssert.fails(
			instance.withdrawAll({from: accounts[1]}),
			truffleAssert.ErrorType.REVERT
		);
		
	}); 
})
1 Like

OnlyOwner test Assignment:

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

contract("People", accounts => {
   it("Should create a person.", async function(){
       let instance = await People.deployed();

       await instance.createPerson(
           "Bob",
           50,
           190,
           {value: web3.utils.toWei("1", "Ether"), from: accounts[1]}
       );
   });

   it("Should not allow non-owner to delete person", async function(){
       let instance = await People.deployed();
       
       await truffleAssert.fails(
           instance.deletePerson(accounts[1], {from: accounts[2]}),
           truffleAssert.ErrorType.REVERT
       );
   });

   it("Should delete person as the owner", async function(){
       let instance = await People.deployed();
       let result = await instance.deletePerson(accounts[1], {from: accounts[0]})
       
       truffleAssert.eventEmitted(
           result,
           "personDeleted",
           {name: "Bob", senior:false, deletedBy:accounts[0]}
       );
   });

});
1 Like

Value assignment:

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

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

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

    it("Should create a person.", async function(){
        await truffleAssert.passes(instance.createPerson(
           "Bob",
           50,
           190,
           {value: web3.utils.toWei("1", "Ether"), from: accounts[1]}
        ));

        let internalBalance = await instance.balance();
        let contractBalance = await web3.eth.getBalance(instance.address);
        let oneEth = parseInt(web3.utils.toWei("1", "Ether"));

        assert(parseInt(internalBalance) === oneEth, 'Internal balance is not correct');
        assert(parseInt(contractBalance) === oneEth, 'Contract balance is not correct');
    });

    it("Should not be able to withdraw to non-owner", async function(){
        await truffleAssert.reverts(instance.withdrawAll({from: accounts[1]}));

        let internalBalance = await instance.balance();
        let contractBalance = await web3.eth.getBalance(instance.address);
        let oneEth = parseInt(web3.utils.toWei("1", "Ether"));

        assert(parseInt(internalBalance) === oneEth, 'Internal balance is not correct');
        assert(parseInt(contractBalance) === oneEth, 'Contract balance is not correct');
    })

    it("Should be able to withdraw to the owner", async function(){
        await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));

        let internalBalance = await instance.balance();
        let contractBalance = await web3.eth.getBalance(instance.address);

        assert(parseInt(internalBalance) === 0, 'Internal balance is not correct');
        assert(parseInt(contractBalance) === 0, 'Contract balance is not correct');
    })
});
1 Like

@filip Hello everyone,

I hope all is well with you. If someone has an idea of my issue that would be greatly appreciated. I was going along with the lessons and started to notice an issue through my terminal right at the lesson when I created a new instance of the contract for this test. Here is the specific part of the lesson:

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

It gave me this error specifically:

  0 passing (380ms)
  1 failing

  1) Contract: People
       should allow the owner to delete people:
     AssertionError: Failed with Error: Returned error: VM Exception while processing transaction: revert
      at passes (node_modules/truffle-assertions/index.js:142:11)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)
      at Context.<anonymous> (test/peopletest.js:122:5)

During the lesson it seemed that the way to fix it was to remove the await from the line 122:
await truffleAssert.passes(instance.deletePerson(accounts[1], {from: accounts[0]}));

I was having a hard time troubleshooting this so I ended up copying the solution code and tried it again. It seemed there was a trend giving me an error for every function that had the new instance of the contract let instance = await People.new(); where there was an await in front of certain lines.

Thank you for the help and happy new year to you all!

@filip

This is getting VERY annoying! The lessons are poorly prepared, with a lot of errors and corrections.
I did just finish the first section and finally everything passed after a lot of issues.

Now after importing people.sol (I did redo the lesson twice) I get new errors. The first was regarding the artifacts…

…another the version of Solidity.

This might be trivial issues if you have some experience, but I have not enough.

Why does Ownable.sol compile twice?

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

contract("People", (accounts) => {
  it("Should create a new person and delete it with owner address only.", async () => {
    const instance = await People.deployed();
    let ownerAddress = accounts[0];
    let creatorAddress = accounts[1];
    let otherAddress = accounts[2];
    await truffleAssertions.passes(
      instance.createPerson("mock_name", 22, 156, {
        value: web3.utils.toWei("1", "ether"),
        from: accounts[2],
      })
    );
    await truffleAssertions.fails(
      instance.deletePerson(creatorAddress, {
        from: otherAddress,
      })
    );
    await truffleAssertions.fails(
      instance.deletePerson(creatorAddress, {
        from: creatorAddress,
      })
    );
    await truffleAssertions.passes(
      instance.deletePerson(creatorAddress, {
        from: ownerAddress,
      })
    );
  });
});

ExtendableError: Unknown network “ganache”. See your Truffle configuration file for available networks. I havn’t changed anything in my config file besides the solc version for pragma 0.5.12

I have real headache because of this error, is it just a runtime error?
And how come I get it know when it worked fine earlier. stucked for days on this issue, any help is welcomed!

Hey @Paul_Mun

The issue you are facing is related to a require statement in your contract that is failing.
Please post your smart contract.

1 Like

Hey @BERGLUND

The error you are facing is most likely related to a mistake in the migration file.
Can you post your migration?

Thanks

1 Like

Hey @Lamar

Follow these steps and let me know if they fix the issue:

  • Open Ganache and link your project (if you are using Ganache GUI);
  • Navigate into your root project folder by using your terminal;
  • Run truffle migrate --reset;
  • Run truffle console;

Keep me posted,
Dani

THANKS 1000x. The problem is I did not know where to look for error(s). I found an extra ; and this was it. But it was your guidance to the migration file that solved the problem.

1 Like

Owner test assignment


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

contract("People", async function(accounts){
  it("shouldn't create a person with age over 150 years.", async function(){
    let instance = await People.deployed();
    await truffleAssert.fails
    (instance.createPerson("Bob",200,190,{value: web3.utils.toWei("1", "ether")}),truffleAssert.ErrorType.REVERT);
  });
  it("shouldn't create a person without payment.", async function(){
    let instance = await People.deployed();
    await truffleAssert.fails
    (instance.createPerson("Bob",200,190,{value: 1000}),truffleAssert.ErrorType.REVERT);
  });
  it("should set senior status and age correctly", async function(){
    let instance = await People.deployed();
    await instance.createPerson("Bob",65,190,{value: web3.utils.toWei("1", "ether")});
    let result = await instance.getPerson();
    assert(result.senior == true && result.age.toNumber() === 65, "Senior level not set");
  });
  it("should set age correctly", async function(){
    let instance = await People.deployed();
    let result = await instance.getPerson();
    assert(result.age.toNumber() === 65, "Age not set correctly");
  });
  it("should not be deleted by non-owner", async function(){
    let instance = await People.deployed();
    await truffleAssert.fails(instance.deletePerson(accounts[0],{from: accounts[1]}),truffleAssert.ErrorType.REVERT);
  });
  it("should be deleted by owner", async function(){
    let instance = await People.deployed();
    await instance.deletePerson(accounts[0]);
    let result = await instance.getPerson();
    assert(result.name === "" && result.age == 0 && result.height == 0, "Person not deleted")
  });
});