0

Im getting myself into smartcontract development using solidity, I wrote the below smart contract and I have some issues with the Chai and Mocha test for the first function addCandidate()

//SPDX-License-Identifier: GPL-3.0
 
pragma solidity >=0.5.0 <0.9.0;

contract VotingContract{
    address public moderator;
    
    struct Candidate {
        uint256 id;
        string  name;
        uint256 voteCount;
    }
    
    struct Voter {
        string name;
        mapping(address => bool)  hasVoted;
    }
    
    mapping(address => Voter) public votes;
    mapping(uint256 => Candidate) public candidateLookup; //candidates will be identified with an unique ID
    uint256 public candidateCount; //Will be used to track the number of candidates
    
    enum State {beforeStart, running, halted} 
    State public electionState;
    
    event AddedCandidate(string _name);
    event Voted( uint256 id, string _name);

    
    constructor () {
        moderator = msg.sender;
        electionState = State.beforeStart;
        candidateCount = 0; //Not really necesary to initalize to zero as per solidity documentation -> A variable which is declared will have an initial default value whose byte-representation is all zeros. The “default values” of variables are the typical “zero-state” of whatever the type is. For example, the default value for a bool is false. The default value for the uint or int types is 0
    }
    
    
    modifier onlyModerator{
        require(msg.sender == moderator, 'Only the moderator of the election can use this function');
        _;
    }
    
    modifier votingInProcess {
        require(electionState == State.running, 'The election is not active at this moment');
        _;
    }
    
    
    function addCandidate(string memory _name) public onlyModerator returns(bool){
        Candidate storage newCandidate = candidateLookup[candidateCount];
        newCandidate.id = candidateCount;
        newCandidate.name = _name;
        newCandidate.voteCount = 0;
        candidateCount++;
        emit AddedCandidate(_name);
        return true;
    }
    
    function getCandidate(uint256 _id) public view returns(uint256, string memory){
       string memory name = candidateLookup[_id].name;
       uint256 voteCount = candidateLookup[_id].voteCount;
       return (voteCount, name);
    }
    
    function getCandidates() external view returns(string[] memory, uint256[] memory){
        string [] memory names = new string[](candidateCount);
        uint256[] memory voteCounts = new uint[](candidateCount);
        for (uint256 i = 0; i < candidateCount; i++) {
            names[i] = candidateLookup[i].name;
            voteCounts[i] = candidateLookup[i].voteCount;
        }
        return (names, voteCounts);

    }
    
    
    function startVoting() external onlyModerator {
        electionState = State.running;
    }
    
    function haltVoting() external onlyModerator {
        electionState = State.halted;
    }
    
    function vote(uint256 _id, string memory _name) public votingInProcess returns (bool){
        Voter storage newVoter = votes[msg.sender];
        require(_id >= 0 && _id <= candidateCount, 'There is no candidate with the specified ID');
        require(newVoter.hasVoted[msg.sender] == false, 'You can only vote one time!');
        candidateLookup[_id].voteCount++;
        newVoter.name = _name;
        newVoter.hasVoted[msg.sender] = true;
        emit Voted(_id, _name);
        return true;
    }
}

This is the test I have done so far


//getting the contract json representation
const VotingContract = artifacts.require('./VotingContract');
const BN = web3.utils.BN;

let instance;
let accounts;
let owner;

contract('VotingContract', async(accs) => {
    accounts = accs;
    moderator = accounts[0];
})


it('Can add a candidate', async() => {
    let instance = await VotingContract.deployed();
    let id = 0;
    let newCandidateName = 'Candidate1'
    await instance.addCandidate(newCandidateName, {from: moderator});
    let request = await instance.candidateLookup.call(id)
    assert.equal(request, newCandidateName)
});

But it fails, this is what I receive

  1) Can add a candidate

  0 passing (489ms)
  1 failing

  1) Can add a candidate:
     AssertionError: expected { Object (0, 1, ...) } to equal 'Candidate1'
      at Context.<anonymous> (test\VotingContract.test.js:21:12)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

I dont understand from where does the { Object (0, 1, ...) } comes from,

Can any one point me in the right direction? What is this? What documentation should I read? Any additional feedback about the smartcontract I developed will be appreciated!

1

The candidateLookup is mapping of a uint to Candidate (a struct) and not to string (candidateName). So accessing candidateLookup will always returns a struct.

You can try

assert.equal(request[1], newCandidateName)

because a per your struct definition;

request[0]: id,
request[1]: name,
request[2]: voteCount
1
  • Ohhhh, you are right! Thanks Prashant! yup, the test is passing now :) – Antonio Salazar May 12 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.