-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Loïc Vincent-Genod
committed
Sep 3, 2021
0 parents
commit 1542c87
Showing
52 changed files
with
38,918 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": ["react-app", "react-app/jest"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"useTabs": false, | ||
"tabWidth": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"]); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
Oops, something went wrong.