hey @ghiasi12reza
Can you post your truffle config?
happy learning,
Dani
My first thoughtâŚ
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
contract("People", async function(accounts){
it("You should be the owner of the contract in order to delete a person correctly", async function(){
let instance = await People.deployed();
await instance.createPerson("John", 65, 190, {value: web3.utils.toWei("1","ether")});
let createdPerson = await instance.getPerson();
let createrAddress = await instance.getCreator(0);
await instance.deletePerson(createrAddress);
let deletedPerson = await instance.getPerson(); //
assert(createdPerson.name != deletedPerson.name && accounts[0] === createrAddress, "Delete function failed or you are not the owner!");
});
});
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* truffleframework.com/docs/advanced/configuration
*
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
// const HDWalletProvider = require('truffle-hdwallet-provider');
// const infuraKey = "fj4jll3k.....";
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
// development: {
// host: "127.0.0.1", // Localhost (default: none)
// port: 8545, // Standard Ethereum port (default: none)
// network_id: "*", // Any network (default: none)
// },
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
// ropsten: {
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
// network_id: 3, // Ropsten's id
// gas: 5500000, // Ropsten has a lower block limit than mainnet
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
// },
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: "0.5.12", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
// evmVersion: "byzantium"
// }
}
}
}
For checking the value of balance in the contract object and the records in the block:
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
contract("People", async function(accounts){
let instance;
BeforeEach(async function(){
let instance = await People.new();
});
it("Balance Info should be matched between variable of balance in the contract and the balance registered in the block.",async function(){
await instance.createPerson("John", 65, 190, {value: web3.utils.toWei("1","ether")});
let balanceInContract = await instance.getBalance();
let balanceInBlock = await web3.eth.getBalance(instance.address);
assert(balanceInContract == balanceInBlock, "Balance Info is not matched");
});
it("Balance in the contract should be zero after withdraw opration", async function(){
await instance.createPerson("John", 65, 190, {value: web3.utils.toWei("1","ether")});
await instance.createPerson("Mary", 25, 156, {value: web3.utils.toWei("1","ether")});
let createrAddress = await instance.getCreator(0);
let ownerBalance_BeforeWithdraw = await web3.eth.getBalance(createrAddress);
await instance.withdrawAll();
let ownerBalance_AfterWithdraw = await web3.eth.getBalance(createrAddress);
let balanceInContract = await instance.getBalance();
let balanceOfContractOnBlock = await web3.eth.getBalance(instance.address);
assert(balanceInContract == balanceOfContractOnBlock && ownerBalance_AfterWithdraw > ownerBalance_BeforeWithdraw, "Balance in the contract is not zero after withdrawing or Something wrong with Owner");
});
});
Hi @ghiasi12reza,
It looks like you need to add ganache to the ânetworksâ section in your truffle-config.js like so:
ganache: {
host: "127.0.0.1",
port: 7545,
network_id: 5777
},
Hope this helps.
owner test assignment for the deletePerson function
(not using 1 ether, just 1000000 wei for payments)
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
contract("People", async function(accounts) {
it ("should be able to delete a person - it is the owner", async function() {
let instance = await People.deployed();
await instance.createPerson("Alice", 23, 180, {value: 1000000, from: accounts[0]});
await truffleAssert.passes(instance.deletePerson(accounts[0], {from: accounts[0]}));
});
it ("should not delete a person - it is not the owner", async function() {
let instance = await People.deployed();
await instance.createPerson("Alice", 20, 170, {value: 1000000, from: accounts[0]});
await truffleAssert.fails(instance.deletePerson(accounts[1], {from: accounts[1]}),
truffleAssert.ErrorType.REVERT);
});
});
the result:
Contract: People
â should be able to delete a person - it is the owner (274ms)
â should not delete a person - it is not the owner (309ms)
value assignment for createPerson and Withdrawal
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
contract("People", async function(accounts) {
let instance;
beforeEach(async function() {
instance = await People.new();
});
it("should increase the balance after creating a new person", async function() {
await instance.createPerson("Alice", 20, 170, {value: 1000000});
let currentBalance = parseFloat(await instance.contractBalance.call());
let addressBalance = parseFloat(await web3.eth.getBalance(instance.address));
assert((currentBalance == 1000000) && (addressBalance == 1000000), "error: the contract balance has not been increased correctly");
});
it("should not do a withdrawal - it is not the owner", async function() {
await instance.createPerson("Alice", 22, 177, {value: 1000000});
await truffleAssert.fails(instance.withdrawAllTransfer({from: accounts[1]}),
truffleAssert.ErrorType.REVERT);
})
it("should leave the balance at 0 after withdrawing", async function() {
await instance.createPerson("Alice", 23, 178, {value: 1000000, from: accounts[0]});
await instance.withdrawAllTransfer();
let currentBalance = parseFloat(await instance.contractBalance.call());
let addressBalance = parseFloat(await web3.eth.getBalance(instance.address));
assert(currentBalance == 0 && addressBalance == 0, "error: contract balance is not 0");
});
});
the result:
Contract: People
â should increase the balance after creating a new person (263ms)
â should not do a withdrawal - it is not the owner (448ms)
â should leave the balance at 0 after withdrawing (380ms)
I decided to call the createPerson() function again to show an example where I add to the people list via another account so I can have two entries (one was created from a previous test following Filipâs code).
My first test attempts to delete the first person from the list but using a non-owner address, this ends up failing as intended, thus passing the test.
I then test whether the age of a specific Person we delete has reset to zero. This time I run the deletePerson() function via the owner address to get rid of Aliceâs entry from the list. I finally compare the age of the entry to check whether it is zero. This test also passed successfully which means that the deletePerson() function is working as it should.
Final results:
EDIT:
Even though checking the age after deletion also verifies that the original owner of the contract can delete people from the list. I have decided to create a test which explicitly checks whether or not the owner can delete people:
I use .passes() function which expects that the argument to calling deletePerson() will succeed if I delete Bobâs entry from the list. I use the ownerâs address in which case the test succeeds and so we know that the owner can delete people from the list.
Result:
After testing all the above cases with correct and non-correct inputs the tests fail and succeed as they should.
Intended inputs and usage of the functions lead to passing of tests as expected:
Only Owner unit testing:
Update: forgot to include some of the test scenarios on my first post.
On the owner withdrawal, I wanted to verify that the owner balance was accurate including the gas fees so I spent some time researching and came up with an answer. Maybe there is an easier way to do this?
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");
contract("People", async function(accounts) {
let instance;
const owner = accounts[0];
before(async function() {
instance = await People.deployed();
});
it("should not allow a non-owner to withdrawal funds, transaction should revert", async function() {
instance = await People.new();
await instance.createPerson("Mary", 25, 98, {value: web3.utils.toWei("1", "ether"), from: accounts[4]});
await truffleAssert.reverts(instance.withdrawAll({from: accounts[4]}), "revert",
"Only the Owner can withdraw funds.");
});
it("should allow the owner to withdrawal funds", async function() {
instance = await People.new();
await instance.createPerson("Mary", 25, 98, {value: web3.utils.toWei("1", "ether"), from: accounts[4]});
await truffleAssert.passes(instance.withdrawAll({from: owner}));
});
it("should increase owner's balance by contract balance amount after withdrawal", async function() {
instance = await People.new();
await instance.createPerson("Mary", 25, 98, {value: web3.utils.toWei("1", "ether"), from: accounts[4]});
const startAccountBalanceBN = web3.utils.toBN(await web3.eth.getBalance(owner));
const contractBalanceBN = web3.utils.toBN(await instance.balance());
const gasPriceBN = web3.utils.toBN(web3.utils.toWei("40",'gwei'));
let tx = await instance.withdrawAll({from: owner, gasPrice: gasPriceBN});
const gasCostBN = web3.utils.toBN(tx.receipt.gasUsed).mul(gasPriceBN);
const endAccountBalance = await web3.eth.getBalance(owner);
const finalBalanceBN = startAccountBalanceBN.add(contractBalanceBN).sub(gasCostBN);
assert(finalBalanceBN == endAccountBalance, "Balance mismatch.");
});
it("should reset contract balance to 0 after withdrawal", async function() {
instance = await People.new();
await instance.createPerson("Mary", 25, 98, {value: web3.utils.toWei("1", "ether"), from: accounts[4]});
await instance.withdrawAll({from: owner});
const contractBalance = await instance.balance();
const chainBalance = await web3.eth.getBalance(instance.address);
assert(contractBalance == web3.utils.toWei("0", "ether") && contractBalance == chainBalance,
"Contract balance is not 0.");
});
})
Owner test assignment:
it("Should verify contract owner when deleting person.", async function() {
let instance = await People.deployed();
await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
await truffleAssert.fails(
instance.deletePerson(accounts[0], {from: accounts[1]}),
truffleAssert.ErrorType.REVERT);
await truffleAssert.passes( instance.deletePerson(accounts[0], {from: accounts[0]}));
});
Iâve searched a lot online yesterday for a confirmation that using multiple truffleAssert statements in a single test was working as expected and did not find any.
For this reason I will follow the way presented in the solution in the future. Until I have more knowledge.
Just wanted to give a come back on my answer.
Thank you
I used the same code to do the age test (âBobâ,200,190) with truffleAssert but I always get this result
I do not understand why, despite the fact that I used the same People code and also the same test file. @filipTruffle is saying that the variable instance
does not have a function createPerson()
.
Can you post your test.js file?
happy coding
Hi @filip
I have a question! Below is my code for the value assignment.
It is working but when I saw your answer I thought I need to use parseFloat when I compare the amount in the account. But when I checked in the console it showed NaN when I tried to convert. Can I have advice? Thank you.
// Create a test to check the change in the balance of the contract
it(âshould increase the amount of cash in the contractâ,async function(){
let amountBefore = await web3.eth.getBalance(instance.address);
await instance.createPerson(âJaneâ,65,190,{value:web3.utils.toWei(â1â, âetherâ)});
let amountAfter = await web3.eth.getBalance(instance.address);
assert(amountAfter > amountBefore,âthe amount should increaseâ);
});
// Create a test to check that the owner can withdrawal the amount in the account
it(âshould allow the owner to withdrawalâ, async function(){
await instance.createPerson(âJackyâ,75,180,{value:web3.utils.toWei(â1â, âetherâ)});
await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}),âOwner can withdraw all.â);
});
// Create a test to check that the non-owner cannot withdrawal the amount in the account
it(âshould allow the owner to withdrawalâ, async function(){
await instance.createPerson(âJackyâ,75,180,{value:web3.utils.toWei(â1â, âetherâ)});
await truffleAssert.fails(instance.withdrawAll({from: accounts[1]}));
});
Hi @filip
I have another question.
I am a bit confused about the difference between the below two.
In the video you said the top 2 lines are referring to the balance recorded in the contract and the last one is the one is recorded in the blockchain.
Can you a little bit elaborate on this? I was thinking that I was checking from the same place, from the blockchain.
let balance = await instance.balance();
let floatBalance = parseFloat(balance);
let realBalance = await web3.eth.getBalance(instance.address);
Thank you,
Jun
Amazing!! I found it!
ontract("People", async function(accounts){
let owner = accounts[0];
let user = accounts[2];
...
deletePerson()
functionit("should allow the Owner to delete user[2]", async function(){
let instance = await People.deployed();
await instance.deletePerson(user, {from: owner});
});
it("should not allow user[2] to delete himself", async function(){
let instance = await People.deployed();
await instance.deletePerson(user, {from: user});
});
RESULTS are OK!
here is the test.js code :
const People = artifacts.require(âPeopleâ);
const truffleAssert = require(âtruffle-assertionsâ);
contract(âPeopleâ, async function(){
it(âit shouldnât create a Person over 150 yearsâ, async function(){
let instance = People.deployed();
await truffleAssert.fails(instance.createPerson(âBobâ, 200, 190, {value : web3.utils.toWei(â1â,âetherâ)}));
})
});
I found the problem, I forgot await, thankâs in advance.
The test of address (in order to make sure that only the owner can delete the created Person).
it(âit should assert that only the Owner can delete the contractâ,async function(){
let owner = accounts[0];
let creator = owner;
let user = accounts[1];
let instance = await People.deployed();
await instance.deletePerson( creator,{from :accounts[0]});
})
it(âit should assert that only the Owner can delete the contractâ,async function(){
let owner = accounts[0];
let creator = owner;
let user = accounts[1];
let instance = await People.deployed();
await truffleAssert.fails(instance.deletePerson( creator,{from :accounts[1]}));
})