Skip to main content

Writing Tests

This section presents the main technical elements to setup, write and run tests.

Project

Create project

Completium CLI provides the create project command to set up a simple project with contracts and tests.

The command below creates a project named myproject:

completium-cli create project myproject

This creates the myproject directory with the following structure:

myproject
├── contracts
│   └── hello.arl
├── package.json
├── tests
│   └── 00-test-hello.ts
└── tsconfig.json

The project comes with a default contract hello.arl and its test 00-test-hello.ts.

The package.json contains the declaration of required packages. They are installed with:

$ cd myproject
$ npm i

Note that there are 2 directories of interest:

  • contracts to store smart contracts (Archetype or Michelson)
  • tests to store tests (Typescript)

Generate binding

A contract's binding is generated automatically for each contract found in contracts directory. A binding is a typescript object that reflects the contract interface to interact with it in read/write modes.

The following command generates one binding file per contract (Archetype or Michelson) found in contracts directory:

npm run gen-binding

In the default setup, this generates the file hello.ts in tests/binding/ directory from hello.arl in contracts directory.

These values are defined in the "completium" section of the package.json file:

package.json
"completium": {
"binding_path": "./tests/binding/",
"build_path": "./build/",
"contracts_path": "./contracts/",
"tests_path": "./tests/"
}

Modify these values to adapt to your setup.

danger

Bindings need to be generated with the above command everytime the contract interface is modified (storage, entries, views, error messages)

Run tests

The following command executes tests found in tests directory:

npm run test

This executes tests in 00-test-hello.ts file and generates the following output:

> ts-mocha --timeout 0 --slow 99999999 ./tests/*.ts

[HELLO] Contract deployment
✔ Deploy test_binding

[HELLO] Call entry
✔ Call 'myentry'

2 passing (2s)

The test command is defined in package.json as:

"scripts" : {
"test": "ts-mocha --timeout 0 --slow 99999999 ./tests/*.ts"
}

Note that It is possible to create a new rule in the scripts section to run a specific test file.

info

The mockup mode must be initialised with the completium-cli mockup init command for the test command to run. More information here.

Configuration

By default, the global Completium CLI configuration (network, account, quiet mode, ...) is used by a test. It is possible to overwrite the configuration with dedicated functions from @completium/experiment-ts package.

Network

The set_mockup function set the mockup mode.

import { set_mockup } from "@completium/experiment-ts"

set_mockup()

Another network (test, ghostnet) may be set with the set_network function.

Account

Calling a contract's entry point require to specify the caller account. An account is declared with Completium CLI (see here for information). An account is referred to with an alias.

The get_account function returns a Completium account from its alias.

import { get_account } from "@completium/experiment-ts"

const alice = get_account('alice')
info

The mockup mode comes with a set of 8 predefined accounts ready to use for test purposes: alice bob carl bootstrap1 bootstrap2 bootstrap3 bootstrap4 bootstrap5

Now

When contract logic relies on the now value, test scenarios require to change its value. The @completium/experiment-ts package provides with the following utility functions:

Now utilities


Sets mockup now value.


Delays mockup now value by a number of days.


Delays mockup now by a number of minutes.


Delays mockup now by a number of hours.


Delays mockup now by a number of seconds.


Delays mockup now by a number of weeks.


Gets mockup now value.


info

These utility functions are only available in mockup mode.

Quiet mode

The set_quiet function switchs on or off the quiet mode. When set to false, the output of the tezos-client (in mockup mode) is displayed with detailed information, like gas consumption and storage diffs.

import { set_quiet } from "@completium/experiment-ts"

set_quiet(true)

Test structure

The default project created with create project command uses the Mocha test package. You are free to install and use any other testing framework, like Jest.

In the Mocha testing framework, the describe function is used to group together related tests. It takes two arguments: a string description of the test group, and a callback function that contains the individual tests or further nested describe blocks.

Here is an example of how describe is used:

describe('A group of tests', function() {
// Test cases go here
})

The it function is used to define a single test case within a describe block. It takes two arguments: a string description of the test, and a callback function containing the code for the test.

Here is an example of how it is used:

describe('A group of tests', function() {
it('should do something', function() {
// Test code goes here
})
})

Together, describe and it are used to structure and organize your tests in Mocha. The describe function is used to group together related tests, while the it function is used to define individual test cases.

For example, the following example from 00-test-hello.ts :

describe('[HELLO] Call entries', async () => {
it("Call 'exec'", async () => {
await hello.exec({ as : alice })
const s_after = await hello.get_s()
assert(s_after === "Hello Archetype World!")
})
it("Call 'exec2'", async () => {
await hello.exec2({ as : alice })
const s_after = await hello.get_s()
assert(s_after === "Hello TS Binding World!")
})
})

Then the output looks like:

[HELLO] Call entry
✔ Call 'exec'
✔ Call 'exec2'

Failing test

When the call to a contract's entry point is expected to fail, the function expect_to_fail catches the contract error and compares it to the expected one passed in parameter. It fails if the actual error is different from the expected one, or if the contract does not fail.

The expect_to_fail function takes two arguments: a callback function that executes the call to the entry point expected to fail, and the expected error.

For example, consider the following mint entry point of fa2_nft contract:

entry mint(tow : address, tid : nat, tmd: map<string, bytes>) {
called by owner
effect {
/* ... */
}
}

The following expects the call to mint as bob to fail with error INVALID_CALLER:

import { expect_to_fail } from '@completium/experiment-ts'

// ...

it('Mint tokens on FA2 as non owner should fail', async () => {
await expect_to_fail(async () => {
await fa2_nft.mint(
bob.get_address(), // owner
token_id, // token id
[['', new Bytes('')]], // metadata
{ as: bob });
}, fa2_nft.errors.INVALID_CALLER);
});

Note that the errors field of contract's binding interface is the list of possible errors (here fa2_nft.errors).

Batch

It is possible to batch call contract entry points with the exec_batch function. It takes transaction parameters returned by dedicated binding methods as presented here.

Utils

@completium/experiment-ts and @completium/archetype-ts-types packages the binding generation relies on, also provide some utility functions presented below. See the full packages API here.

Experiment


Hashes bytes data accourding to blake2b algorithm.


Signs packed data.


Packs bytes data.


Transfers tez from one account to another.


Type Utils


Compares javascript dates at second precision (as Tezos dates are).


Tests whether a Micheline or value is left.


Tests whether a Micheline or value is right.