Learn how to test a simple counter contract using the Clarinet JS SDK.
In this quickstart guide, you will initialize a simulated development network for testing a smart contract using the Clarinet JS SDK. You'll learn how to initialize your project, interact with a smart contract, call its functions, and test the results.
Check out the methods page for the Clarinet JS SDK to learn about the different ways that you can interact with simnet.
Before we dive in, navigate to your project and import the Cl helper from the @stacks/transactions package in your test file.
counter.clar
counter.test.ts
.gitignore
Clarinet.toml
package.json
tsconfig.json
vitest.config.js
The Cl namespace simplifies the process of creating and handling Clarity values. This functionality is particularly useful in testing environments where developers need to simulate contract interactions accurately.
For most test cases, you'll want to retrieve an account from the network in order to interact with your smart contracts. The following code uses the getAccounts method to achieve this.
counter.test.ts
import{ describe, expect, it }from"vitest";
import{ Cl }from"@stacks/transactions";
constaccounts=simnet.getAccounts();
constwallet=accounts.get("wallet_1")!;
Note
The --stacks flag is required and allows you to specify the network to scan. Other options include --bitcoin.
The process for writing tests for smart contracts with the Clarinet JS SDK follows a structured approach similar to testing in JavaScript. Here's a breakdown of the steps involved:
1Define the group of tests you want to run using the describe block.
2Define the test you want to run using the it block.
3Call the function and assert the result using the expect function.
Now that you understand the key components for writing tests, start by writing a test that ensures the counter contract has been deployed.
Now it's time to call a public function and assert the result. The count-up function is expected to increment the count of the user's principal by 1. Write a test to ensure this behaves as expected.
counter.test.ts
describe("counter contract", ()=>{
it("increments the count of the user's principal by 1", ()=>{
Above, the count-up function is called, and the result is asserted to return an (ok true). Then, the count for the user's principal is retrieved and asserted to be u1.
Custom matchers
The toBeOk and toBeUint methods are used to ensure the count-up function returns the proper Clarity values. For more details, check out the custom matchers page.
Clarinet can automatically also produce a code coverage report and cost analysis on the test you ran.
package.json
"scripts": {
"test":"vitest run",
"test:report":"vitest run -- --coverage --costs",
"test:watch":"chokidar\"tests/**/*.ts\" \"contracts/**/*.clar\"-c\"npm run test:report\""
}
By running the npm run test:report command in your terminal, an lcov.info and costs-reports.json file will appear in your root folder:
counter.clar
counter.test.ts
.gitignore
Clarinet.toml
costs-reports.json
lcov.info
package.json
tsconfig.json
vitest.config.js
The costs-reports.json file will output the cost analysis for every function ran in your tests. Since the count-up function was used in our test, this is how the cost analysis output would look like for that function:
costs-reports.json
{
"test_name":"tests/counter.test.ts__counter contract__increments the count of the user's principal by 1",
To access and read the lcov.info file in a human-readable format, we can first install the lcovpackage that helps generate a graphical front-end for coverage testing tools.
Terminal
$
brew install lcov
Then we'll run the genhtml command below with the following options. This command and its options will generate the actual html file, add in additional branch coverage, and will automatically store the files in a new folder called coverage.
Terminal
$
genhtml lcov.info --branch-coverage -o coverage
You can then navigate into the new coverage folder and run the command open index.html to view your coverage report. In addition, a summary of the coverage report will be outputted in the terminal.