LimeChain / matchstick

🔥 Unit testing framework for Subgraph development on The Graph protocol. ⚙️
MIT License
207 stars 17 forks source link

Use `createMockedFunction` to mock a function returning a tuple #417

Closed alainncls closed 10 months ago

alainncls commented 10 months ago

Hi,

I'm trying to use the createMockedFunction method to mock a contract call that returns a tuple, but I keep hitting errors.

Here is a short extract of my test file:

// Create an array of values
const tupleArray: Array<ethereum.Value> = [
    ethereum.Value.fromAddress(Address.fromString("f75be6f9418710fd516fa82afb3aad07e11a0f1b")),
    ethereum.Value.fromAddressArray([Address.zero()]),
    ethereum.Value.fromBoolean(true),
    ethereum.Value.fromString("string"),
  ];

// Convert it to the Tuple type
const tuple = changetype<ethereum.Tuple>(tupleArray);

// Create a tuple Value
const tupleValue = ethereum.Value.fromTuple(tuple as ethereum.Tuple);

// Mock the call to the contract
createMockedFunction(
  Address.fromString("506f88a5Ca8D5F001f2909b029738A40042e42a6"),
  "getTuple",
  "getTuple(address):((address,address[],bool,string))",
)
  .withArgs([ethereum.Value.fromAddress(Address.fromString("f75be6f9418710fd516fa82afb3aad07e11a0f1b"))])
  .returns([tupleValue]);

test("Should mock the call to TupleContract", () => {
  const contract = TupleContract.bind(Address.fromString("506f88a5Ca8D5F001f2909b029738A40042e42a6"));
  const result = contract.getTuple(Address.fromString("f75be6f9418710fd516fa82afb3aad07e11a0f1b"));

  assert.tupleEquals(tuple, result);
});

But when I run this test, I get the following error:

ERROR AS100: Not implemented: Closures
       .returns([tupleValue]);
                 ~~~~~~~~~~~~~~~~
 in tests/tuple-contract.test.ts(32,17)

What am I missing? Is there any issue with my code or is this a limitation of the framework?

Many thanks in advance for your help! 🙏

dimitrovmaksim commented 10 months ago

Try removing the as ethereum.Tuple part from const tupleValue = ethereum.Value.fromTuple(tuple as ethereum.Tuple);

You have already casted it as tuple here const tuple = changetype<ethereum.Tuple>(tupleArray);

alainncls commented 10 months ago

Good catch! This simplified my code a bit.

To solve my issue, I finally understood that I had to wrap my mock setup in a beforeAll block!
In the end, my code looks like that and works smoothly:

import { beforeAll, createMockedFunction, describe } from "matchstick-as";
import { Address, ethereum } from "@graphprotocol/graph-ts";

describe("handleTupleCall()", () => {
  beforeAll(() => {
    // Create an array of values
    const tupleArray: Array<ethereum.Value> = [
      ethereum.Value.fromAddress(Address.fromString("f75be6f9418710fd516fa82afb3aad07e11a0f1b")),
      ethereum.Value.fromAddressArray([Address.zero()]),
      ethereum.Value.fromBoolean(true),
      ethereum.Value.fromString("string"),
    ];

    // Convert it to the Tuple type
    const tuple = changetype<ethereum.Tuple>(tupleArray);

    // Create a tuple Value
    const tupleValue = ethereum.Value.fromTuple(tuple);

    // Mock the call to the contract
    createMockedFunction(
      Address.fromString("506f88a5Ca8D5F001f2909b029738A40042e42a6"),
      "getTuple",
      "getTuple(address):((address,address[],bool,string))",
    )
      .withArgs([ethereum.Value.fromAddress(Address.fromString("f75be6f9418710fd516fa82afb3aad07e11a0f1b"))])
      .returns([tupleValue]);
  });

  test("Should mock the call to TupleContract", () => {
    const contract = TupleContract.bind(Address.fromString("506f88a5Ca8D5F001f2909b029738A40042e42a6"));
    const result = contract.getTuple(Address.fromString("f75be6f9418710fd516fa82afb3aad07e11a0f1b"));

    assert.tupleEquals(tuple, result);
  });
});

Thanks a lot for your help @dimitrovmaksim !