0

I've been working with the voting contract example, and been unit testing it with Truffle and Javascript. So far I have managed to test every function from my contract with success. But when i tried to retrieve the candidateList property it didn't work. Part of the testing file

...
it('returns every candidate', async () => {
    let fundRaise = await Voting.new(['Alice', 'Bob', 'Rick']);

    const cands = await voting.candidateList();
    Console.log(cands);
});
...

When i execute the above test, truffle shows the following

1) Contract: Voting returns every candidate:
 Error: Invalid number of arguments to Solidity function
  at Object.InvalidNumberOfSolidityArgs (/usr/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/errors.js:25:1)
  at SolidityFunction.validateArgs (/usr/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:74:1)
  at SolidityFunction.toPayload (/usr/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:90:1)
  at SolidityFunction.call (/usr/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:131:1)
  at SolidityFunction.execute (/usr/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:260:1)
  at /usr/lib/node_modules/truffle/build/webpack:/~/truffle-contract/contract.js:135:1
  at new Promise (<anonymous>)
  at /usr/lib/node_modules/truffle/build/webpack:/~/truffle-contract/contract.js:126:1
  at <anonymous>
  at process._tickDomainCallback (internal/process/next_tick.js:228:7)

What i don't get is why if the getter function is generated automatically, web3 is throwing this message. I have Truffle v4.1.7 (core: 4.1.7); Solidity v0.4.23 (solc-js); Geth/v1.8.1-stable-1e67410e/linux-amd64/go1.9.4"; web3 version api: '0.20.6',

Below is the contract file as well, as the testing file.

pragma solidity ^0.4.17;

contract Voting {

mapping (bytes32 => uint8) public votesReceived;
bytes32[] public candidateList;

constructor(bytes32[] _candidates) public {
    candidateList = _candidates;
}

function voteForCandidate(bytes32 _name) public returns (uint8) {
    require(validateCandidate(_name));
    votesReceived[_name] += 1;
    //return votesReceived[_name];
    return totalVotesFor(_name);
}

function validateCandidate(bytes32 _name) view public returns (bool){
    for (uint8 i = 0; i < candidateList.length; i++) {
        if(candidateList[i] == _name){
            return true;
        }
    }
    return false;
}

function totalVotesFor(bytes32 name) view public returns (uint8){
    require(validateCandidate(name));
    return votesReceived[name];
}

function addCandidate(bytes32 _name) public returns (bool) {
    candidateList.push(_name);
    return validateCandidate(_name);
}


const assert = require('assert');
var Voting = artifacts.require("Voting");

This is the testing file:

contract('Voting', function(accounts) {

let voting;

beforeEach(async () => {
    voting = await Voting.deployed();
});

it('votes for valid candidate', async () => {

    const voto = await voting.voteForCandidate.call('Andrea');

    assert.equal(voto.toNumber(),1, 'Cannot vote for valid candidate');
});

it('Does not vote for invalid candidate', async () => {
    const voto = await voting.voteForCandidate.call('Bacilio');

    assert.equal(voto.toNumber(), 0, 'Allowed to vote for invalid candidate');
});

it('Adds new candidate', async () => {
    const voto = await voting.addCandidate.call('Segismundo');
    assert.equal(voto, true, 'Did not allow to add new candidate');
});

it('allows to obtain votes casted for a candidate', async () => {

    const expected_votes = 2;

    //vote twice for the same candidate
    await voting.voteForCandidate('Roberto');
    await voting.voteForCandidate('Roberto');

    let casted_votes = await voting.totalVotesFor.call('Roberto');
    assert.equal(casted_votes.toNumber(), expected_votes, 'Did not got casted votes')

});

it('returns every candidate', async () => {
    let fundRaise = await Voting.new(['Segismundo', 'Ocatvia']);

    const cands = await voting.candidateList();
    Console.log(cands);
});

});
1

In your Solidity code, add:

function candidateListLength() external view returns (uint) {
    return candidateList.length;
}

In your Javascript code add:

let cands = [];
let length = Number(await voting.candidateListLength());
for (let i = 0; i < length; i++)
    cands.push(await voting.candidateList(i));
  • It worked, thanks! Just to be clear, whenever you want to access a contract's array variable. You must provide a specific index to obtain, getting the whole array is not supported? – Roberto C. May 8 '18 at 6:15
  • Not AFAIK...... – goodvibration May 8 '18 at 6:21

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.