description |
---|
In this tutorial, you'll learn how to use Foundry's 'cheatcodes'—special commands that allow you to test and manipulate blockchain states. We'll focus on the `vm.expectEmit` cheatcode to test events. |
- Use the
vm.expectEmit
Cheatcode - Test a Solidity event
Before you begin, you should be familiar with the following:
Also, you should have the following set up on your computer ⬇
- git installed
- Minimum version: 2.37
- Recommended: Install Git (Github)
- A code editor or IDE
- Recommended: VS Code. Install VS Code (Visual Studio)
- NodeJs + npm installed
- Minimum version of NodeJs: 18
- Minimum version of npm: 9.5
- Recommended for Linux & Mac: nvm
- Recommended for Windows: nvm-windows
- foundry
forge
andcast
installedforge
Minimum version: 0.2.0cast
Minimum version: 0.2.0
Check your prerequisites set up ⬇
Open your terminal, and enter the following commands.
git --version
code --version
node --version
npm --version
forge --version
cast --version
Each of these commands should output some text that includes a version number, for example:
git --version
git version 2.39.2 (Apple Git-143)
code --version
1.81.1
6c3e3dba23e8fadc360aed75ce363ba185c49794
arm64
node --version
v20.6.1
npm --version
9.8.1
forge --version
0.2.0 (6fcbbd8 2023-12-15T00:29:51.472038000Z)
cast --version
0.2.0 (6fcbbd8 2023-12-15T00:29:51.851258000Z)
If the output contains text similar to command not found
, please install that item.
To follow along, start with the main
branch,
which is the default branch of this repository.
This gives you the initial state from which you can follow along
with the steps as described in the tutorial.
{% hint style="warning" %} Learn how to setup foundry by completing the Setup Foundry and Write a Basic Unit Test tutorial. This tutorial will not walkthrough setting up Foundry. {% endhint %}
forge
manages dependencies by using git submodules. Clone the following project and pass --recurse-submodules
to the git clone
command to automatically initialize and update the submodule in the repository.
git clone --recurse-submodules [email protected]:hedera-dev/test-an-event-with-foundry.git
forge install
Open the project test-an-event-with-foundry
, in a code editor.
If you completed the previous tutorial, you may notice the contents of the contract TodoList.sol
have changed. Specifcally, there is a CreateTodo event that has been declared and is emitted in the createTodo()
function.
An almost-complete test has already been prepared for you. It's located at test/TodoList.t.sol
.
You will only need to make a few modifications (outlined below)
for it to run successfully.
{% hint style="warning" %} Look for a comment in the code to locate the specific lines of code which you will need to edit. For example, in this step, look for this: // Step (1) in the accompanying tutorial You will need to delete the inline comment that looks like this: /* ... */. Replace it with the correct code. {% endhint %}
Declare the CreateTodo
event in your test contract. This event is identical to the one that is declared in TodoList.sol
.
event CreateTodo(address indexed creator, uint256 indexed todoIndex, string description);
Grab the number of todos, as it will be used to create the expected event according to the current state of the contract.
uint256 numberOfTodosBefore = todoList.getNumberOfTodos();
The cheatcode vm.expectEmit()
will be used to check if the event is emitted.
This cheatcode expects four inputs:
bool checkTopic1
asserts the first indexbool checkTopic2
asserts the second indexbool checkTopic3
asserts the data for index 3bool checkData
asserts the remaining data emitted by the eventaddress emitter
asserts the emitting address matches
The event being tested includes two indexed arguments: address indexed creator
and uint256 indexed todoIndex
. Therefore, we want to assert the matching of topic 1, topic 2, the non-indexed data, and the emitting address with our actual event.
vm.expectEmit(true, true, false, true, address(todoList));
Emit the expected event with the following parameters:
- the
creator
of the todo is this test contract with address0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496
, - the
todoIndex
is the currentnumberOfTodos
+ 1, - the
description
is set to "a new todo."
emit CreateTodo(address(this), numberOfTodosBefore + 1, 'a new todo');
Execute TodoList.sol
's createTodo()
function.
todoList.createTodo(address(this), 'a new todo');
forge test --match-test test_emit_createTodoEvent -vvvv
You should see output similar to the following:
[⠢] Compiling...
No files changed, compilation skipped
Running 1 test for test/TodoList.t.sol:TodoListTest
[PASS] test_emit_createTodoEvent() (gas: 84576)
Traces:
[84576] TodoListTest::test_emit_createTodoEvent()
├─ [2325] TodoList::getNumberOfTodos() [staticcall]
│ └─ ← 0
├─ [0] VM::expectEmit(true, true, false, true, TodoList: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f])
│ └─ ← ()
├─ emit CreateTodo(creator: TodoListTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], todoIndex: 1, description: "a new todo")
├─ [70920] TodoList::createTodo(TodoListTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], "a new todo")
│ ├─ emit CreateTodo(creator: TodoListTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], todoIndex: 1, description: "a new todo")
│ └─ ← 1
└─ ← ()
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.10ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)
The test passed and shows the event is working as expected.
Congratulations, you have completed how to test a solidity event using Foundry. You have learned how to:
- Use the vm.expectEmit Cheatcode
- Test a Solidity event
Writer: Abi Castro, DevRel Engineer | https://twitter.com/ridley___ |
Editor: Michael Garber, Developer Advocate | https://twitter.com/michaelgarber87 |