Learn how to write and run comprehensive unit tests for your Clarity smart contracts using the Clarinet JS SDK and Vitest.
Deployment plans minimize the inherent complexity of deployments, such as smart contract dependencies and interactions, transaction chaining limits, deployment costs, and more, while ensuring reproducible deployments critical for testing purposes.
Let us consider a counter smart contract to understand how to write unit tests for our application requirements.
First, create a new Clarinet project with a counter contract.
Below will be the content of our smart contract.
It keeps track of an initialized value, allows for incrementing and decrementing, and prints actions as a log.
Create a file tests/counter.test.ts with the following content:
To run the test, go back to your console and run the npm test command. It should display a report telling you that tests succeeded.
There is a very important thing happening under the hood here. The simnet object is available globally in the tests, and is automatically initialized before each test.
You don't need to know much more about that, but if you want to know in detail how it works, you can have a look at the vitest.config.js file at the root of you project.
Getting back to the tests, we just implemented two of them:
The first test checks that the increment function returns the new value and saves it to the count variable.
The second test checks that an print_event is emitted when the increment function is called.
You can use Cl.prettyPrint(value: ClarityValue) to format any Clarity value into readable Clarity code. It can be useful to debug function results or event values.
Note that we are importing describe, expect and it from Vitest.
it allows us to write a test.
describe is not necessary but allows to organize tests.
expect is use to make assertions on value.
You can learn more about Vitest on their website.
We also implemented some custom matchers to make assertions on Clarity variables (like toBeUint).
The full list of custom matchers is available at the end of this guide.
Comprehensive Unit Tests for counter
Let us now write a higher coverage test suite by testing the decrement and get-counter functions.
These two code blocks can be added at the end of tests/counter.test.ts.
To help developers maximize their test coverage, the test framework can produce a lcov report, using --coverage flag. You can set it in the scripts in the project package.json:
Then run the script with the following command. It will produce a file named ./lcov.info.
From there, you can use the lcov tooling suite to produce HTML reports.
The test framework can also be used to optimize costs. When you execute a test suite, Clarinet keeps track of all costs being computed when executing the contract-call, and displays the most expensive ones in a table.
To help developers maximize their test coverage, the test framework can produce a lcov report, using --coverage flag. You can set it in the scripts in the project package.json:
And run the script with the following command. It will produce a file named ./costs-reports.json.
For now, there isn't much you can do out of the box with a costs report. But in future versions of the Clarinet JS SDK, we will implement features to help keep track of your costs, such as checking that function calls do not go above a certain threshold.