Unit Testing in Truffle

I’m struggling with this one. I played around a bit with the migration files and added the accounts feature and then added a test but im not sure if its actually working honestly. I think im going to have to watch the solution and then come back and try to do it from scratch without looking.

Anybody else in my shoes?
I feel as though i’m understanding the concepts but when I have to write it on my own my brain is blank on how to execute the task … any suggestions?

1 Like
  it("Shouldn't delete from non-owner address", async () => {
    let nonOwner = accounts[1];
    let instance = await People.deployed();
    instance.deletePerson(nonOwner);
    let result = await instance.getPerson();
    assert(result.name === "Bob", "Person was deleted from non-owner address");
  });
  it("Should delete from owner address", async () => {
    let owner = accounts[0];
    let instance = await People.deployed();
    instance.deletePerson(owner);
    let result = await instance.getPerson();
    assert(result.name=== "", `Should have been deleted ${result.name}`);
  });

Better way


it("Shouldn't delete from non-owner address", async () => {
    let nonOwner = accounts[1];
    let instance = await People.deployed();
    await instance.createPerson("KJ", 31, 190, { from: nonOwner, value: web3.utils.toWei("1", "ether") });
    await truffleAssert.fails(instance.deletePerson(nonOwner, { from: nonOwner }), truffleAssert.ErrorType.REVERT);
  });
  it("Should delete from owner address", async () => {
    let owner = accounts[0];
    let nonOwner = accounts[1];
    let instance = await People.deployed();
    await truffleAssert.passes(instance.deletePerson(nonOwner, { from: owner }), truffleAssert.ErrorType.REVERT);
  });
1 Like

Yeah I struggled a bit. If you’re new to programming like I am then just remind yourself that even just understanding what you’re reading and wrapping you’re head around what you have to do is awesome work already!! I feel like I am in a similar situation as you, I understand what I have to achieve but figuring out the syntax and terms for each of the different languages (like this project incorporating solidity for the program but javascript for the testing) is the difficult part. I can only imagine exposure and repetition will get this down for the both of us before to long.

If you still haven’t watched the video, then the following 2 points below might help…they were the bits I got stuck on.

  1. In the Value Assignment testing, it took me a couple of hours of searching the interwebs for how to refer to the contract address, I tried a heap of different approaches as I couldn’t find it too easily. Once I finally discovered it was as simple as ‘instance.owner’ testing was finally possible…(you would use whatever variable name you instantiated + .address
 let instance = await Balances.new();
//or
 let instance = await Balances.deployed();
//or even
let contractEventOccurence = await Balances.deployed()

//then late in code you can refer to it with .address to get the
//occurence of the contract deployment's address...e.g.
let contractBalance = await web3.eth.getBalance(instance.address);
//or
let contractBalance = await web3.eth.getBalance(contractEventOccurence.address);
  1. I did not figure out how to successfully compare some of the balances in my testing until I watched the solutions video where the ‘parseFloat’ concept was shared.
    This is needed for numbers to be compared correctly by different programs I think, something to do with programs interpreting numbers differently (floating point numbers I am assuming) and by using the parseFloat() function, the comparison of balances from blockchain to JS testing became possible.
    Anyways, I think I’ve understood and hopefully shared this idea correctly. All of that said, no you are not the only one that struggled with it. Took me quite some time and didn’t solve all of it without help. My take home is - even if you have to watch the solution vid or check solutions in this thread, make sure you return to it after a day or 2 and try and do it all fresh from memory. When I did the JavaScript course, I did the tests from the Eloquent Javascript chapters like 3 times each over a couple of weeks. Helped to cement the concepts and syntax for me by waiting a week or so and then trying it again from scratch.
    Good on you for reaching out, you’re definitely not on your own with this, the community here seems really helpful too so keep at it and we’ll all push through together.
    Good luck mate.
2 Likes

Thanks @cryptocrom I really appreciate the thoughtful response and I will try some of those tips. I didnt watch the solution video yet, so I will try this first and see how far I can get. Like you I am new to programming also. I learned some basics of python and javascript on codecademy before starting the course here, but I think like you said its all about practice and repetition. Will follow up later after I try this some more. thanks again - Cody

1 Like

@filip @Taha Since the function toNumber() is used (which is supposed to convert numbers into integers) in result.age.toNumber() in the following code: https://github.com/filipmartinsson/solidity-201/blob/master/finaltests.js

Does this mean if we set the age to 65 it does not get stored as 65 and instead gets stored as something else?

If so, what number does this get stored as?

@filip @Taha I am working on the Owner Test Assignement and have a question. How do I access the msg.sender of the person who called a function?

So far I have the following:


 it("only owner should be able to delete people", async function(){
    await instance.deletePerson(accounts[0]);
	  assert(msg.sender === owner, "Sender not owner. Only owner should be able to delete people");
  }

I would like to access msg.sender of the person that called the deletePerson function to compare it with the owner. How do I do that?

Hi CryptoBuddha,

Your assertion should already be a requirement of the deletePerson function so it can’t be anything other than the msg.sender with out it failing, in this case you could just have accounts[1] === owner in the assertion but you would need to wrap it in truffleAssert.fails() not assert(). Side note: this won’t actually fail if you change ownership to accounts[1] prior.

Also, this assertion doesn’t really test whether a created person was deleted successfully or not. You could try creating a person (lets say “Alice”) and then delete Alice and test to see if Alice has been deleted or not by asserting that Alice no longer has a name, for example:

Create a Person first, then instantiate a variable with the getPerson function for the person that was created, i.e.
let createdPerson = await instance.getPerson();
then you can refer to the created person’s name through the instantiated variable.name to get the person’s name, e.g.
await instance.createdPerson.name
you could then asser that this name is == "Alice" and then delete this person and assert that this name is now equal to nothing instead of “Alice” i.e. == ""

You could then try deleting the person from a different account by using a second argument {from: } in the delete function which will tell the program who is calling the function (I suspect this is what you were trying to get at in your message as how to change the msg.sender). This argument defaults to account 0 when no argument is provided, but we can provide one like this:

await instance.deletePerson(accounts[0], {from: accounts[4]});

then an assertion that Alice is still named Alice will be true and a truflleAssert.fails function that specifies that Alice is no longer named Alice will work as you would expect this name not to have been deleted by anyone other than account[0] (the owner).

Hope this helps

2 Likes

@CodyM
Its completely fine to look at the solution :slight_smile:
That is why the solution is already given.
Programming is not an overnight experience, it gradually develops.

Yes, almost everyone has been in your shoes.

2 Likes

@cryptocrom

  1. Amazing to see you find out by yourself, this also helps you become independent in the space and now you know where and how to channelize your searches to make your dApp work :slight_smile:
  2. In every programming languages there are different data types such as string, int, uint, float, boolean, etc.
    float is a data type which takes number with decimal places and is not there is solidity programming language but it is available in JS.
    So comparing balances which will be mostly in decimal numbers, it is best to convert the variable into data type float using the function parsefloat()

Hope this helps

2 Likes

Awesome,thanks for the clarification, I thought it was something like that - I just can’t seem to be doing of the words into the sentence putting as nicely as you haha. Cheers

1 Like

@CryptoBuddha
msg.sender basically means the sender of the message (to the EVM), message is nothing but a transaction. So, which ever account is calling the deletePerson() is msg.sender :slight_smile:

Also, @cryptocrom really well answered and thank you for the reply :slight_smile:

2 Likes

Cheers, I remember being encouraged to help out if we knew an answer to a question and saw an opportunity to help give some pointers and tips (hopefully without giving too much away). It was actually good for me to try to explain the code out to someone, helped me to cement the knowledge by putting it into words.

1 Like

@CryptoBuddha

result.age.toNumber() has converted result.age into integer data type.
If you set the age to 65, it takes it a integer data type and not string or something else. And also stores as 65 (integer).

Hope this answers the question

1 Like

Assignment: Owner Test

const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
contract("People", async function(accounts){
  it("should not allowed to delete people to non-owner", async function(){
    let instance = await People.deployed();
    await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[0]});
    await truffleAssert.fails(instance.deletePerson(accounts[1],{from:accounts[1]}), truffleAssert.ErrorType.REVERT);
    });
  it("should allowed owner to delete people", async function(){
    let instance = await People.deployed();
    await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[0]});
    await truffleAssert.passes(instance.deletePerson(accounts[1],{from:accounts[0]}));
  })
  });

1 Like

Assignment : Value

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("should increase balance when create person with 1 ether", async function(){
    let instance = await People.new();
    await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[1]});
    let balance = await instance.balance();
    let oldBalance = parseFloat(balance);
    let newBalance = await web3.eth.getBalance(instance.address);
    assert(oldBalance == web3.utils.toWei("1","ether") && oldBalance == newBalance)
  });
  it("contract owner can withdraw funds", async function(){
    let instance = await People.new();
    await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[2]});
    await truffleAssert.passes(instance.withdrawAll({from:accounts[0]}));
  });
  it("contract non-owner can't withdraw funds", async function(){
    let instance = await People.new();
    await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[2]});
    await truffleAssert.fails(instance.withdrawAll({from:accounts[1]}), truffleAssert.ErrorType.REVERT);
  });
  it("contract balance should goes to zero after withdrawal", async function(){
    let instance = await People.new();
    await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[2]});
    await instance.withdrawAll();
    let balance = await instance.balance();
    let oldBalance = parseFloat(balance);
    let newBalance = await web3.eth.getBalance(instance.address);
    assert(oldBalance == web3.utils.toWei("0", "ether") && oldBalance == newBalance, "Contract balance should be 0 or not match")
  });
  it("owners balance should increse after withdrawal", async function (){
  let instance = await People.new();
  await instance.createPerson("Jan",100, 190,{value: web3.utils.toWei("1", "ether"), from: accounts[2]});
  let oldBalance = parseFloat(await web3.eth.getBalance(accounts[0]));
  await instance.withdrawAll();
  let newBalance = parseFloat(await web3.eth.getBalance(accounts[0]));
  assert(oldBalance < newBalance, "Owners balance not increased");
  });
});
1 Like

Unit Test Exercise

it("deletePerson-01", async function()
	{
		let theContract = await PEOPLE.deployed();
		await theContract.createPerson("Test-04", 65, 190, {from: inAccounts[1], value: web3.utils.toWei("1", "ether")});
		let thePerson = await theContract.getPerson({from: inAccounts[1]});
		assert(thePerson.name === "Test-04", "Expected: Test-04 Actual: " + thePerson.name);
		await theContract.deletePerson(inAccounts[1]);
	});

	it("deletePerson-02", async function()
	{
		let theContract = await PEOPLE.deployed();
		await theContract.createPerson("Test-05", 65, 190, {from: inAccounts[1], value: web3.utils.toWei("1", "ether")});
		let thePerson = await theContract.getPerson({from: inAccounts[1]});
		assert(thePerson.name === "Test-05", "Expected: Test-05 Actual: " + thePerson.name);
		await TRUFFLE_ASSERT.fails(theContract.deletePerson(inAccounts[1], {from: inAccounts[1]}),
			TRUFFLE_ASSERT.ErrorType.REVERT);
	});
1 Like
  it("should let owner delete person", async function(){
    let instance = await People.deployed();
    await assert(instance.deletePerson(accounts[0]), "owner can't delete person");
  });

  it("shouldn't let not owner address delete person", async function(){
    let instance = await People.deployed();
    People.owner = 0x5DBC50bbAebE14F775131090412d4A3cec0910da; //address from accounts[3]
    await truffleAssert.fails(instance.deletePerson(accounts[0]), truffleAssert.ErrorType.REVERT);
  });

second test should fail, but doesn’t
I don’t know how to modify the owner var in .js

Help! Had this trouble since the beginning of unit testing category.
Contract compiles and deploys but test comes back with:

TypeError [ERR_INVALID_REPL_INPUT]: Listeners for uncaughtException cannot be used in the REPL
at process. (repl.js:256:15)
at process.emit (events.js:327:22)
at process.emit (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\build\webpack:\node_modules\source-map-support\source-map-support.js:495:1)
at processEmit (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\build\webpack:\node_modules\signal-exit\index.js:155:1)
at process.emit (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\build\webpack:\node_modules\reselect-tree\node_modules\source-map-support\source-map-support.js:485:1)
at _addListener (events.js:358:14)
at process.addListener (events.js:406:10)
at Runner._addEventListener (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\node_modules\mocha\lib\runner.js:200:10)
at Runner.run (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\node_modules\mocha\lib\runner.js:1033:8)
at Mocha.run (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\node_modules\mocha\lib\mocha.js:1002:17)
at C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\build\webpack:\packages\core\lib\test.js:159:1
at new Promise ()
at Object.run (C:\Program Files (x86)\node-v12.18.3-win-x64\node_modules\truffle\build\webpack:\packages\core\lib\test.js:158:1)
at runMicrotasks ()
at processTicksAndRejections (internal/process/task_queues.js:97:5)

  it("balance in contract is the same as ballance on blockchain", async function(){
    let instance = await People.new();

    await instance.createPerson("Mike", 65, 190, {from: accounts[0], value: web3.utils.toWei("1", "ether")});
    await instance.createPerson("Jill", 65, 190, {from: accounts[0], value: web3.utils.toWei("1", "ether")});

    await truffleAssert.passes(await instance.balance() === await web3.eth.getBalance(await instance.address), {from: accounts[0]}, "ballances are not the same");
  });
  it("should let owner withdrawAll and ballances should be the same in contract & on blockchain", async function(){
    let instance = await People.new();

    await instance.createPerson("Julia", 65, 190, {from: accounts[0], value: web3.utils.toWei("1", "ether")});
    await instance.createPerson("Tom", 65, 190, {from: accounts[0], value: web3.utils.toWei("1", "ether")});

    await instance.withdrawAll();
    await truffleAssert.passes( (await instance.balance() === await web3.eth.getBalance(await instance.address)) && (await instance.balance() === 0), {from: accounts[0]}, "ballances are not the same");
  });

also checked with lots of console.log()-s, looks to be working fine

@Archie_Smyth
there must be some error messages above “TypeError [ERR_INVALID_REPL_INPUT]” that are more suggestive
possibly if you reinstall node.js, it can fix it:

npm un -g truffle
npm i -g truffle@nodeLTS
1 Like