Testing Aztec.nr contracts with TypeScript
In this guide we will cover how to interact with your Aztec.nr smart contracts in a testing environment to write automated tests for your apps.
Prerequisites
- A compiled contract with TS interface (read how to compile)
- Your sandbox running (read getting started)
Create TS file and install libraries
Pick where you'd like your tests to live and create a Typescript project.
You will need to install Aztec.js:
yarn add @aztec/aztecjs
You can use aztec.js
to write assertions about transaction statuses, about chain state both public and private, and about logs.
Import relevant libraries
Import aztecjs
. This is an example of some functions and types you might need in your test:
import { createAccount, getDeployedTestAccountsWallets } from '@aztec/accounts/testing';
import {
type AccountWallet,
CheatCodes,
ExtendedNote,
Fr,
Note,
type PXE,
TxStatus,
computeSecretHash,
createPXEClient,
waitForPXE,
} from '@aztec/aztec.js';
Source code: yarn-project/end-to-end/src/guides/dapp_testing.test.ts#L1-L15
You should also import the Typescript class you generated:
import { TestContract } from '@aztec/noir-contracts.js/Test';
Source code: yarn-project/end-to-end/src/guides/dapp_testing.test.ts#L16-L18
Create a PXE client
Currently, testing Aztec.nr smart contracts means testing them against the PXE that runs in the local sandbox. Create a PXE client:
const pxe = createPXEClient(PXE_URL);
await waitForPXE(pxe);
Source code: yarn-project/end-to-end/src/guides/dapp_testing.test.ts#L28-L31
and use the accounts that are initialized with it:
pxe = createPXEClient(PXE_URL);
[owner, recipient] = await getDeployedTestAccountsWallets(pxe);
token = await TokenContract.deploy(owner, owner.getCompleteAddress(), 'TokenName', 'TokenSymbol', 18)
.send()
.deployed();
Source code: yarn-project/end-to-end/src/guides/dapp_testing.test.ts#L81-L87
Alternatively, you can create a new account..
Write tests
Calling and sending transactions
You can send transactions within your tests with Aztec.js. Read how to do that in these guides:
Using debug options
You can use the debug
option in the wait
method to get more information about the effects of the transaction. This includes information about new note hashes added to the note hash tree, new nullifiers, public data writes, new L2 to L1 messages, new contract information, and newly visible notes.
This debug information will be populated in the transaction receipt. You can log it to the console or use it to make assertions about the transaction.
const receiptClaim = await txClaim.wait({ debug: true });
Source code: yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts#L87-L89
You can also log directly from Aztec contracts. Read this guide for some more information.
Examples
A private call fails
We can check that a call to a private function would fail by simulating it locally and expecting a rejection. Remember that all private function calls are only executed locally in order to preserve privacy. As an example, we can try transferring more tokens than we have, which will fail an assertion with the Balance too low
error message.
const call = token.methods.transfer(recipient.getAddress(), 200n);
await expect(call.prove()).rejects.toThrow(/Balance too low/);
Source code: yarn-project/end-to-end/src/guides/dapp_testing.test.ts#L195-L198
Under the hood, the send()
method executes a simulation, so we can just call the usual send().wait()
to catch the same failure.
const call = token.methods.transfer(recipient.getAddress(), 200n);
await expect(call.send().wait()).rejects.toThrow(/Balance too low/);
Source code: yarn-project/end-to-end/src/guides/dapp_testing.test.ts#L202-L205