Is there a way to test on a local blockchain with OpenZeppelin Test Environment?

Hi, I’m wondering if there’s a way to automate test for testnet in a similar way to testing on a local blockchain with test-environment and test-helpers?

1 Like

Hi @minhdinh1,

With OpenZeppelin Test Environment you can fork an existing blockchain (such as mainnet or a public testnet) and run your tests against that network.

See the documentation for details on configuring fork: https://docs.openzeppelin.com/test-environment/0.1/getting-started#fork_and_unlocked_accounts

In order to fork an existing blockchain, do I need to deploy my contract up to the testnet first and use the block number after? And what does unlocked-accounts mean in the documentation you mentioned.
Sorry, I’m still new to smart contract testing

1 Like

Hi @minhdinh1,

Your tests will deploy your contracts to the local fork of the blockchain.

unlocked_accounts is an array of accounts that you want to unlock so that you can send transactions from these accounts.

Hi,

I’ve tried changing the test environment config in test-environment.config.js to fork from rinkeby testnet but it all of the test just fail at the setup token stage with this error.
1) LuniverseGluwacoin_Initialization
“before each” hook for “token name is LuniverseGluwacoin”:
Uncaught Error: Unhandled server error
at Object.default_1 [as default] (node_modules/@openzeppelin/test-environment/src/setup-ganache.ts:69:15)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at /mnt/c/Work/WSL_files/Luniverse-Gluwacoin/node_modules/@openzeppelin/test-environment/src/test-provider.ts:20:19
at run (node_modules/p-queue/dist/index.js:163:29)
Is there any more steps that I need to take to successfully run my test code on rinkeby testnet the same way it ran on the local blockchain?

My node packages version are:
npm 6.14.6
truffle v5.1.49
mocha 8.2.0
test-helper 0.5.7
test-environment 0.1.5

1 Like

Hi @minhdinh1,

If your tests run locally then you just need to change your test-environment.config.js to include what you want to fork. As per: https://docs.openzeppelin.com/test-environment/0.1/getting-started#fork_and_unlocked_accounts

I used Infura, but you could use Alchemy or another provider, see: https://docs.openzeppelin.com/learn/connecting-to-public-test-networks#accessing-a-testnet-node.

Testing against a fork takes time, so I recommend increasing the timeout.

Please find below a simple example I used:

test-environment.config.js

// test-environment.config.js
const { infuraProjectId, } = require('./secrets.json');

module.exports = {
  node: { // Options passed directly to Ganache client
    fork: `https://rinkeby.infura.io/v3/${infuraProjectId}`, // An url to Ethereum node to use as a source for a fork
  },
};

secrets.json

I keep my Infura Project ID (or other API key secret) in secrets.json but you could use any secret keeping approach (:exclamation: don’t commit any secrets to version control)

{
      "infuraProjectId": "MY INFURA PROJECT ID"
}

package.json

Testing against a fork is slow, so recommend increasing the timeout when running mocha.

{
...
  "scripts": {
    "test": "mocha --exit --recursive --timeout 10000"
  },
...
}

Box.sol

From: https://docs.openzeppelin.com/learn/developing-smart-contracts#first-contract

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Box {
    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

Box.test.js

From: https://docs.openzeppelin.com/learn/writing-automated-tests#test-environment

// test/Box.test.js

// Load dependencies
const { accounts, contract } = require('@openzeppelin/test-environment');
const { expect } = require('chai');

// Load compiled artifacts
const Box = contract.fromArtifact('Box');

// Start test block
describe('Box', function () {
  const [ owner ] = accounts;

  beforeEach(async function () {
    // Deploy a new Box contract for each test
    this.contract = await Box.new({ from: owner });
  });

  // Test case
  it('retrieve returns a value previously stored', async function () {
    // Store a value - recall that only the owner account can do this!
    await this.contract.store(42, { from: owner });

    // Test if the returned value is the same one
    // Note that we need to use strings to compare the 256 bit integers
    expect((await this.contract.retrieve()).toString()).to.equal('42');
  });
});

Test

$ npm run test

> minhdinh1@1.0.0 test /home/abcoathup/projects/forum/minhdinh1
> mocha --exit --recursive --timeout 10000



  Box
    ✓ retrieve returns a value previously stored (397ms)


  1 passing (5s)

Thanks, I’m able to run my local tests on the testnet now.
I think the reason why my tests failed before is because settings that are caused through migrations and manually deploying and running contract functions to test on the testnet.
I manage to run my test on testnet by resetting the project to the point before I manually do the things I mentioned above.

1 Like

Hi @minhdinh1,

Glad to hear that you are up and running with your tests.

You could deploy any contracts that you need in a before or beforeEach in your tests.