Error trying to obtain set of fields from array of Solidity objects

I am trying to write a test for the voting example Ballot.sol here:

https://docs.soliditylang.org/en/v0.8.11/solidity-by-example.html

My test code looks like this :

const ethers = require('ethers');

const BallotContract = artifacts.require("Ballot");

contract("BallotPractice", accounts => {

let ballot;

const proposalNames = [ethers.utils.formatBytes32String("Proposal_1"),
                       ethers.utils.formatBytes32String("Proposal_2"),
                       ethers.utils.formatBytes32String("Proposal_3")];

describe("initialization", () => {
   beforeEach (async () => {
     ballot = await BallotContract.new(proposalNames);
    });

it("gets the proposalNames", async () => {

    let agendas = ballot.proposals.map(({item}) => item.name);
    const actual = await agendas;
    assert.equal(actual, proposalNames, "proposalNames should match");
   });
  });
});

I got this error when I ran truffle test:

TypeError: ballot.proposals.map is not a function

I'm still fairly new to Solidity so would appreciate your help.

I'm trying to obtain the list of proposal names from ballot.proposals.

Thanks in advance.

The Ballot.sol code is as follows:

pragma solidity >=0.7.0 < 0.9.0;

/// @title Voting with delegation

contract Ballot {
    // Declare new complex tye to be used for variables later.
    // Represents single voter

    struct Voter {
        uint weight;  // weight can be accumulated by delegation
        bool voted;   // true if person has already voted
        address delegate; // person this voter has delegated their vote to
        uint vote;        // index of the voted proposal
    }

    // Type for a single proposal

    struct Proposal {

        bytes32 name; // short name
        uint voteCount; // number of accumulated votes
    }

    address public chairperson;

    /* 
     * Declare a state variable that
     * stores a Voter struct for each 
     * possible address. 
    */
    mapping(address => Voter) public voters;

    // Dynamically sized array of Proposal structs

    Proposal[] public proposals;

    // Create new ballot to choose one of proposalNames

    constructor(bytes32[] memory proposalNames) {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;
        /*
         * For each of the provided proposal names,
         * create a new proposal and add it 
         * to the end of the array
        */
        for (uint i=0; i < proposalNames.length; i++) {
            // Create Proposal object and append to proposals array
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount:0
                }));
        }
    }

      /*
       * Give voters the right to vote on this ballot.
       * May only be called by the chairperson
       */
       function getRightToVote(address voter) external {
        require(
            msg.sender == chairperson,
            "Only chairperson can grant right to vote"
            );
        require(
            !voters[voter].voted,
            "Voter already voted"
            );
        require(voters[voter].weight==0);
        voters[voter].weight = 1;
       }
     
      // Delegate your vote to the voter to
      function delegate(address to) external {
        // assign reference
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "You already voted");

        require(to != msg.sender, "Self-delegation disallowed");

        /* Walk along the path of potential delegates until the address is 0.
         * This is to handle multiple levels of delegation
         */
        while(voters[to].delegate != address(0)) {
            to = voters[to].delegate;
            // Loop in delegate path not allowed
            require(to != msg.sender, "Loop in delegation encountered");
        }

        sender.voted = true;
        sender.delegate = to;
        Voter storage delegate_ = voters[to];

        if (delegate_.voted) {
            /* If delegate already voted,
             * add to number of votes
            */
            proposals[delegate_.vote].voteCount += sender.weight;
        } else {
            //If the delegate did not vote yet, add to her weight
            
            delegate_.weight += sender.weight;
        }
      }

      // vote function. Give your vote to a specific proposal

      function vote(uint proposal) external {
        Voter storage sender = voters[msg.sender];
        require(sender.weight !=0, "Has no right to vote");
        require(!sender.voted, "Already voted");
        sender.voted = true;
        sender.vote = proposal;

        proposals[proposal].voteCount += sender.weight;

      }
    
      // Compute winning proposal taking all previous votes into account

      function winningProposal() public view
               returns (uint winningProposal_) {

                uint winningVoteCount = 0;
                for (uint p = 0; p < proposals.length; p++ ) {
                    if (proposals[p].voteCount > winningVoteCount) {
                        winningVoteCount = proposals[p].voteCount;
                        winningProposal_ = p;
                    }
                }

            }

       /* Call winningProposal() function to get index of winner
          contained in proposals array and return the name of the winner
        */
       function winnerName() external view returns (bytes32 winnerName_) {
                winnerName_ = proposals[winningProposal()].name;
       }


       function getProposalsLength() external view returns(uint){
         return proposals.length;
       }

       function getProposalByIndex(uint index) external view returns (bytes32){
           return proposals[index].name;
        }



}

Solution 1:

this call is wrong:

 let agendas = ballot.proposals.map(({item}) => item.name);  
  • if you are working with contract always use await

  • I assume proposals is a method in contract. this is how you should call a contract method if it is not modifying state

    let agendas =await  ballot.proposals.call()
    
  • Looks like you want to return an array from the contract directly, but you cannot return array. If proposals is returning an array from contract, i belive it will return the address of the array not array with items. this is how you should return array from the contract

Array returned from Solidity assigned as bigNumber in Javascript