Skip to content

Commit

Permalink
chore: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Loïc Vincent-Genod committed Sep 3, 2021
0 parents commit 1542c87
Show file tree
Hide file tree
Showing 52 changed files with 38,918 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# dependencies
node_modules
.pnp
.pnp.js

# testing
coverage

# production
lib

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["react-app", "react-app/jest"]
}
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/lib

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

.env*
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"useTabs": false,
"tabWidth": 2
}
117 changes: 117 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Eth Testing

A set of tools in order to generate a mock Web3 Provider and simulate blockchain interactions in tests.

The goal is to directly mock the web3 provider level, it implies that it does not make any assumption on what other libraries/packages, such as `web3.js` or `ethers`, are used in order to interact with the remote blockchain.

**❗❗ This is an alpha version ❗❗ Use it at your own risk ❗❗**

## Example

An example of a simple decentralized React application is available in the `example/` folder. It uses `jest` and `@testing-library` for the tests.

## Installation

The recommend way to use Eth-Testing with an application is to install it a development dependency:
```shell
# If you use npm:
npm install eth-testing --save-dev

# Or if you use Yarn:
yarn add eth-testing --dev
```

## Usage and API description

The first step is to generate the utils
```TypeScript
const {
provider,
testingUtils,
generateContractUtils
} = setupEthTesting({ providerType: "MetaMask" });
```
The argument is only the provider type, the two choices for now are `"MetaMask"` or `"default"`.

The provider will then need to be injected in the application, this mechanism depends on the implementation details of the application. As an example for MetaMask, provider is injected in the `window` object so as an example, using `jest` hooks one may inject the mock provider as
```TypeScript
beforeAll(() => {
global.window.ethereum = provider;
});
```

It is strongly advised to clean the mocks between each tests, this may be done using the `clearAllMocks` function exposed through the `testingUtils` object. Again, using `jest` hooks, this can be done as
```TypeScript
afterEach(() => {
testingUtils.clearAllMocks();
});
```

### High levels mocks

High level mocking functions allows anyone, even without a knowledge of the underlying mechanics to properly mock the interactions with the provider/blockchain. This is the advised way to perform mocking.

The available functions for now are described below:
- `mockChainId`: allows to mock the chain ID / network to which the provider is connected
```TypeScript
// Mock the network to Ethereum main net
testingUtils.mockChainId("0x1");
```
- `mockAccounts`: allows to mock the accounts with which the provider is connected
```TypeScript
// Mock the connected account as 0x138071e4e810f34265bd833be9c5dd96f01bd8a5
testingUtils.mockAccounts(["0x138071e4e810f34265bd833be9c5dd96f01bd8a5"]);
```
- `mockChainChanged`: allows to simulate a change in the chain ID / network
```TypeScript
// Simulate a change to the Ropsten network
testingUtils.mockChainChanged("0x3");
```
- `mockAccountsChanged`: allows to simulate a change in the chain ID / network
```TypeScript
// Simulate a change of account to 0xf61B443A155b07D2b2cAeA2d99715dC84E839EEf
testingUtils.mockAccountsChanged(["0xf61B443A155b07D2b2cAeA2d99715dC84E839EEf"]);
```

Additionally, the `generateContractUtils` is exposed from the setup and allows to generate high level utils for contract interactions based on their ABI.
```TypeScript
const abi = [...];
const contractTestingUtils = generateContractUtils(abi);
```

Let us consider a very simple contract
```Solidity
contract Storage {
uint public value;
function setValue(uint newValue) public {
value = newValue;
}
}
```

These utils expose two functions
- `mockCall`: allows to mock the result of a call to a contract using the name of the function to be called and the orderered list of values to be returned
```TypeScript
// Mock a call to the "value" function of the contract and returning the uint 100
contractTestingUtils.mockCall("value", ["100"]);
```
- `mockTransaction`: allows to mock the result of a transaction from a contract method using the name of the function to be called
```TypeScript
// Mock a transaction based from the `setValue` function of the contract
contractTestingUtils.mockTransaction("setValue");
```

### Low levels mocks

These functions handles mock at a lower level, use it at your own risk.
- `emit`: emits a notification for the provider, associated subscribers will be triggered
```TypeScript
// Simulate a change of account to 0xf61B443A155b07D2b2cAeA2d99715dC84E839EEf
testingUtils.lowLevel.emit("accountsChanged", ["0xf61B443A155b07D2b2cAeA2d99715dC84E839EEf"]);
```
- `mockRequest`: registers a mock for a JSON-RPC request
```TypeScript
// Simulate 0x138071e4e810f34265bd833be9c5dd96f01bd8a5 as connected account
testingUtils.lowLevel.mockRequest("eth_accounts", ["0xf61B443A155b07D2b2cAeA2d99715dC84E839EEf"]);
```
25 changes: 25 additions & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

.env
41 changes: 41 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Eth Testing Example Application

This is an example of a React decentralized application. The app connects to Ethereum using MetaMask and allows the user to interact with a simple contract.

The test files demonstrate how to use `eth-testing` with `@testing-library` in order to properly test components and logic interacting with the Ethereum provider.

## Get started

Install the dependencies
```shell
npm install
```

### Run the tests

```shell
npm test
```

There are two tests:
- `header.test.tsx`: about account and network display
- `contract-box.test.tsx`: about contract interaction

### Start the application

1. Launch a development blockchain network using a ganache-cli with one account. If no `PRIVATE_KEY` is given, a random one will be generated.
```shell
PRIVATE_KEY=<MY_PRIVATE_KEY> npm run ganache:start
```
The exposed port of the ganache-cli is `8545`.

2. Deploy the `Storage.sol` contract on the development network
```shell
npm run truffle:deploy
```
Copy the deployed address of the contract and paste it in `src/constants/storage-contract.ts` for the exported `ADDRESS` variable.

3. Run the application
```shell
npm start
```
19 changes: 19 additions & 0 deletions example/contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract Migrations {
address public owner = msg.sender;
uint public last_completed_migration;

modifier restricted() {
require(
msg.sender == owner,
"This function is restricted to the contract's owner"
);
_;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
10 changes: 10 additions & 0 deletions example/contracts/Storage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

contract Storage {
uint public value;

function setValue(uint newValue) public {
value = newValue;
}
}
5 changes: 5 additions & 0 deletions example/migrations/1_initial_migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Migrations = artifacts.require("Migrations");

module.exports = function(deployer) {
deployer.deploy(Migrations);
};
6 changes: 6 additions & 0 deletions example/migrations/2_setup_migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const Storage = artifacts.require("Storage");

module.exports = function(deployer) {
// deployment steps
deployer.deploy(Storage);
};
Loading

0 comments on commit 1542c87

Please sign in to comment.