'i'm trying to make truffle test for this contracts, but i get this error...Error: Returned error: VM Exception while processing transaction: revert

my question is about truffle, i would like to know if someone can help me.

I want to set a vote for one of that presidents, with the second account on ganache(Who deploy the contract(address 0 in ganache) cannot vote).

During Test the error is: Error: Returned error: VM Exception while processing transaction: revert

This are the contracts and test

1 - VotingToken.sol

```
//SPDX-License-Identifier: UNLICENSED

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Voting.sol";
import "./VotingInfo.sol";

pragma solidity ^0.8.4;

contract VotingToken is Ownable, ERC20{

    Voting private voting;
    VotingInfo private votingInfo;

    string private _name;
    string private _symbol;
    uint private _totalSupply;

    mapping(address=>uint)private _balances;

    modifier onlyVoting(){
        msg.sender == address(voting);
        _;
    }


    constructor(string memory name, string memory symbol, uint totalSupply)ERC20(name, symbol){
        _totalSupply = totalSupply;
        _mint(msg.sender, _totalSupply);
        _balances[msg.sender] = _totalSupply;
        _name = name;
        _symbol = symbol;
    }



    function initVotingContract(address _votingAddress)public onlyOwner{
        voting = Voting(_votingAddress);
    }



    function initVotingInfoContract(address _votingInfoContract)public onlyOwner{
        votingInfo = VotingInfo(_votingInfoContract);
    }

    
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override{
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }



    function withdraw()external{
        require(msg.sender != owner(), "Contract Owner cannot withdraw!");
        require(votingInfo.getWhitdrawStatus(msg.sender) == false, "Already withdrawed!");
        uint settedAmount = 1;
        votingInfo.setWithdrawedHappen(msg.sender);
        _transfer(owner(), msg.sender, settedAmount);
        emit Transfer(owner(), msg.sender, settedAmount);
    }


    function tokenAmountAfterVotation(address voter)external onlyVoting{
        _balances[voter] -= 1;
    }


    function balanceOf(address account) public view virtual override returns (uint256){
        return _balances[account];
    }

    function name()public view virtual override returns(string memory){
        return _name;
    }

    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    function totalSupply()public view virtual override returns(uint){
        return _totalSupply;
    }

    function getVotingContractAddress()public view returns(address){
        return address(voting);
    }

    function getVotingInfoContractAddress()public view returns(address){
        return address(votingInfo);
    }
} ```


2 - Voting.sol
``` 
//SPDX-License-Identifier: UNLICENSED


import "@openzeppelin/contracts/access/Ownable.sol";
import "./VotingToken.sol";

pragma solidity ^0.8.4;

contract Voting is Ownable{

    VotingToken private votingToken;
    VotingInfo private votingInfo;

    enum Presidents{Obama, Trump, Biden}

    event FinalResult(
        string firstCandidate,
        uint finalVoteFirst,
        string secondCandidate,
        uint finalVoteSecond,
        string thirdCandidate,
        uint finalVoteThird
        );


    mapping(Presidents=>uint) private Counter;

    constructor(){

    }

    function initVotingTokenContract(address _votingTokenAddress)public onlyOwner{
        votingToken = VotingToken(_votingTokenAddress);
    }

    function initVotingInfoContract(address _votingInfoContract)public onlyOwner{
        votingInfo = VotingInfo(_votingInfoContract);
    }


    function votingObama()external{
        require(votingToken.balanceOf(msg.sender) > 0, "Don't have tokens to vote!");
        require(votingInfo.getUserVotationStatus(msg.sender) != true, "Already made your preference!");
        require(msg.sender != owner(), "Admin cannot vote!");
        votingInfo.setVoteHappen(msg.sender);
        votingToken.tokenAmountAfterVotation(msg.sender);
        Counter[Presidents.Obama] += 1;
    }


    function votingTrump()external{
        require(votingToken.balanceOf(msg.sender) > 0, "Don't have tokens to vote!");
        require(votingInfo.getUserVotationStatus(msg.sender) != true, "Already made your preference!");
        require(msg.sender != owner(), "Admin cannot vote!");
        votingInfo.setVoteHappen(msg.sender);
        votingToken.tokenAmountAfterVotation(msg.sender);
        Counter[Presidents.Trump] += 1;
    }


    function votingBiden()external{
        require(votingToken.balanceOf(msg.sender) > 0, "Don't have tokens to vote!");
        require(votingInfo.getUserVotationStatus(msg.sender) != true, "Already made your preference!");
        require(msg.sender != owner(), "Admin cannot vote!");
        votingInfo.setVoteHappen(msg.sender);
        votingToken.tokenAmountAfterVotation(msg.sender);
        Counter[Presidents.Biden] += 1;
    }


    function getVotingResult()public onlyOwner{
        emit FinalResult(
            "Obama's Final Count ",
            Counter[Presidents.Obama],
            "Trump's Final Count ",
            Counter[Presidents.Trump],
            "Biden's Final Count ",
            Counter[Presidents.Biden]
        );
    }

    function getVotingTokenContract()public view returns(address){
        return address(votingToken);
    }

    function getVotingInfoContract()public view returns(address){
        return address(votingInfo);
    }
}

```

3 - VotingInfo.sol 
```
//SPDX-License-Identifier: UNLICENSED

import "@openzeppelin/contracts/access/Ownable.sol";
import "./Voting.sol";
import "./VotingToken.sol";

pragma solidity ^0.8.4;

contract VotingInfo is Ownable{

    Voting voting;
    VotingToken votingToken;


    mapping(address=>bool)private votedAlready;
    mapping(address=>bool)private withdrawHappen;

    modifier onlyVoting{
        msg.sender == address(voting);
        _;
    }

    modifier onlyVotingToken{
        msg.sender == address(votingToken);
        _;
    }

    constructor(){

    }


    function initVotingContract(address _votingAddress)public onlyOwner{
        voting = Voting(_votingAddress);
    }


    function setVoteHappen(address voter)public onlyVoting{
        votedAlready[voter] = true;
    }

    function getUserVotationStatus(address voter)public view returns(bool){
        return votedAlready[voter];
    }

    function setWithdrawedHappen(address voter)public onlyVotingToken{
        withdrawHappen[voter] = true;
    }

    function getWhitdrawStatus(address voter)public view returns(bool){
        return withdrawHappen[voter];
    }
}
```


Test Starting here...

4 - VotingTokenTest.js

```
const Voting = artifacts.require("Voting");
const VotingInfo = artifacts.require("VotingInfo");
const VotingToken = artifacts.require("VotingToken");


contract("Voting Token", function(accounts){

    it("Should initialize Voting Contract", async () => {
        let deployerAccount = accounts[0];
        let instance = await VotingToken.deployed();
        await instance.initVotingContract(Voting.address);
        let deployer = await instance.owner();
        let addresssVoting = await instance.getVotingContractAddress();
        assert.equal(addresssVoting, Voting.address);
        assert.equal(deployerAccount, deployer);
        console.log("Result is :")
        console.log("Voting Address Setted ", addresssVoting);
        console.log("Voting Address Deployed ", Voting.address);
    })



    it("Should initialize VotingInfo Contract", async () => {
        let deployerAccount = accounts[0];
        let instance = await VotingToken.deployed();
        await instance.initVotingInfoContract(VotingInfo.address);
        let deployer = await instance.owner();
        let addressVotingInfo = await instance.getVotingInfoContractAddress();
        assert.equal(addressVotingInfo, VotingInfo.address);
        assert.equal(deployerAccount, deployer);
        console.log("Result is :");
        console.log("VotingInfo Address Setted ", addressVotingInfo);
        console.log("VotingInfo Address Deployed ", VotingInfo.address);
    })



    it("Check some rest ", async () => {
        let instance = await VotingToken.deployed();
        let name = await instance.name();
        let symbol = await instance.symbol();
        let totalSupply = await instance.totalSupply();
        assert.equal(name, "BABA");
        assert.equal(symbol, "ABBA");
        assert.equal(totalSupply, 10000);
        console.log("Name => ", name)
        console.log("Symbol => ", symbol)
        console.log("Supply => ", parseFloat(totalSupply));
    })



    it("Withdraw token to partecipate at the votation", async () => {
        let instance = await VotingToken.deployed();
        let instanceVotingInfo = await VotingInfo.deployed();
        await instance.withdraw({from: accounts[1]});
        await instanceVotingInfo.setWithdrawedHappen(accounts[1]);
        let getWithdrawStatus = await instanceVotingInfo.getWhitdrawStatus(accounts[1]);
        let owner = await instance.owner();
        let balanceSender = await instance.balanceOf(accounts[1]);
        let ownerBalance = await instance.balanceOf(owner);
        assert.equal(balanceSender, 1);
        assert.equal(ownerBalance, 9999);
        assert.equal(getWithdrawStatus, true);
        console.log("Withdraw Status", getWithdrawStatus);
        console.log("Sender Balance ", parseFloat(balanceSender));
        console.log("Owner Balance ", parseFloat(ownerBalance));
    })
})
```


```const Voting = artifacts.require("Voting");
const VotingInfo = artifacts.require("VotingInfo");
const VotingToken = artifacts.require("VotingToken");


contract("Voting Contract", function(accounts){

    it("Should initialize correctly Voting token Contract", async()=>{
        let deployerAccount = accounts[0];
        let instance = await Voting.deployed();
        await instance.initVotingTokenContract(VotingToken.address);
        let deployer = await instance.owner();
        let addressVotingToken = await instance.getVotingTokenContract();
        assert.equal(addressVotingToken, VotingToken.address);
        assert.equal(deployerAccount, deployer);
        console.log("VotingToken Address Correct!");
    })


    it("Should initialize correctly VotingInfo Contract", async()=>{
        let deployerAccount = accounts[0];
        let instance = await Voting.deployed();
        let deployer = await instance.owner();
        await instance.initVotingInfoContract(VotingInfo.address);
        let addressVotingInfoContract = await instance.getVotingInfoContract();
        assert.equal(addressVotingInfoContract, VotingInfo.address);
        assert.equal(deployerAccount, deployer);
        console.log("VotingInfo Address Correct!");
    })



    it("Should set a vote for Obama", async()=>{
        let instance = await Voting.deployed();
        let votingInfoInstance = await VotingInfo.deployed();
        let votingTokenInstance = await VotingToken.deployed();
        await instance.initVotingTokenContract(VotingToken.address);
        await instance.initVotingInfoContract(VotingInfo.address);
        await votingTokenInstance.withdraw({from:accounts[1]});
        await instance.votingObama({from: accounts[1]});
        await votingInfoInstance.setVoteHappen(accounts[1]);
        await votingTokenInstance.tokenAmountAfterVotation(accounts[1]);

        ===========>>>>> ERROR IS HERE <<<<<===========

    })
})```


Initially i was thinking about a problem refer to the _transfer function in the 
VotingToken.sol, maybe something like the accounts who call the withdraw function, doesn't 
"receive" an allowance to spend that token, but the point now is the Error looks so generic 
and i'm bit stuck on that.
Can someone help me to fix it? thanks in advice and have a good day


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source