Reputation: 181
I am using hardhat with ethers on rinkeby to test a smart contract that makes a a get request to a local chainlink node. I can observe on the node dashboard that the request is fulfilled.
I am struggling to write a test that waits for the 2nd fulfillment transaction to be confirmed.
I see similar tests in the SmartContractKit/chainlink repo tests
it("logs the data given to it by the oracle", async () => {
const tx = await oc.connect(roles.oracleNode).fulfillOracleRequest(...convertFufillParams(request, response));
const receipt = await tx.wait();
assert.equal(2, receipt?.logs?.length);
const log = receipt?.logs?.[1];
assert.equal(log?.topics[2], response);
});
I fail to see that this would wait for the fulfilled transaction at all. In the consumer.sol this function calls there is an event RequestFulfilled, that is emit, but it doesn't seem like this test is listening to it.
Another example I found, ocean protocol request test, accomplishes this by creating a mapping of request id's, an accessor, and a while loop in the test the polls until the request id is found.
it("create a request and send to Chainlink", async () => {
let tx = await ocean.createRequest(jobId, url, path, times);
request = h.decodeRunRequest(tx.receipt.rawLogs[3]);
console.log("request has been sent. request id :=" + request.id)
let data = 0
let timer = 0
while(data == 0){
data = await ocean.getRequestResult(request.id)
if(data != 0) {
console.log("Request is fulfilled. data := " + data)
}
wait(1000)
timer = timer + 1
console.log("waiting for " + timer + " second")
}
});
This makes sense, and I see how it works. However I would like to avoid creating a mapping, and accessor when I imagine there has got to be a more optimal way.
Upvotes: 2
Views: 926
Reputation: 6131
You'd want to look at the hardhat-starter-kit to see examples of working with Chainlink/oracle API responses.
For unit tests, you'd want to just mock the API responses from the Chainlink node.
For integration tests (for example, on a testnet) you'd add some wait parameter for a return. In the sample hardhat-starter-kit, it just waits x number of seconds, but you could also code your tests to listen for events to know when the oracle has responded. This does use events to get the requestId, however, you actually don't have to make a the event yourself, as the Chainlink core code already has this.
it('Should successfully make an external API request and get a result', async () => {
const transaction = await apiConsumer.requestVolumeData()
const tx_receipt = await transaction.wait()
const requestId = tx_receipt.events[0].topics[1]
//wait 30 secs for oracle to callback
await new Promise(resolve => setTimeout(resolve, 30000))
//Now check the result
const result = await apiConsumer.volume()
console.log("API Consumer Volume: ", new web3.utils.BN(result._hex).toString())
expect(new web3.utils.BN(result._hex)).to.be.a.bignumber.that.is.greaterThan(new web3.utils.BN(0))
})
Upvotes: 3