0

I'm cross-posting this from Stack Overflow, since there seems to be more activity here.

I am trying to develop a dApp with Truffle and want to test my smart contract. The contract contains a second contract within it, like so:

pragma solidity >=0.4.21 <0.6.0;

contract SubContract {
    uint public foo;

    constructor() public {
        foo = 0;
    }
}

contract MainContract {
    SubContract public my_contract;

    constructor() public {
        my_contract = new SubContract();
    }
}

I then want to test this contract in Javascript like so:

var MainContract = artifacts.require("./MainContract.sol");

contract("MainContract", function(accounts) {

  it("initializes SubContract contract", function() {
    return MainContract.deployed().then(function(instance) {
      return instance.my_contract;
    }).then(function(subContractInstance) {
       return subContractInstance.foo();
    }).then(function(foo) {
      assert.equal(foo.toNumber(), 0);
    });
  });
});

If I then try to run this test as is, it tells me it cannot access member function foo() of undefined. If I change it from instance.my_contract to instance.my_contract() in the test, it tells me there is no function contract(), even though other fields are accessed through getter methods. What am I missing here to be able to access the SubContract instance?

---EDIT---

Per the suggestions, here's what a working test looks like:

var MainContract = artifacts.require("MainContract");
var SubContract  = artifacts.require("SubContract");

contract("MainContract", async accounts => {
  it("initializes SubContract contract", async() => {
    let instance = await MainContract.deployed();
    let subContractAddress = await instance.my_contract();
    let subContractInstance = await SubContract.at(subContractAddress);
    let foo = await subContractInstance.foo();
    assert.equal(foo.toNumber(), 0);
  });
});
0

First, your declaration of the contract variable is wrong, contract is a reserved keyword in Solidity. Let's say you rename it to SubContract public my_contract.

Second, accessing the my_contract variable through the getter automatically created for it doesn't return a SubContract instance but the address of the contract. So you will need to do the necessary manipulations in your script to interact with the SubContract by fetching its address from the MainContract and creating the correct instance.

  • Thanks for the quick reply. I changed the variable name in the example. Could you give an example of how to fetch the address of the SubContract instance? – AnnaRebecca Apr 19 at 12:12
  • instance.my_contract() – Eli Drion Apr 19 at 12:16
  • That's what I tried - but I still got an error saying that no such function exists – AnnaRebecca Apr 19 at 12:18
  • Specifically: TypeError: instance.my_contract() is not a function – AnnaRebecca Apr 19 at 12:19
  • Should be something like SubContract.at (instance.my_contract()).foo(). – Mikhail Vladimirov Apr 19 at 12:28

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.