Unit testing a NEAR Smart Contract
Overview
- Prerequisites
- Modify Smart Contract
- Modify Unittest
- Troubleshooting
Prerequisites
Objective
- Using a simple near protocol project, modify the source to run unittests against the following smart contract
Import Boilerplate Source
Modify Smart Contract
- Modify the
./assembly/index.ts
file to reflect the code below
import { storage, logging } from "near-sdk-as";
// --- contract code goes below
export function incrementCounter(value: i32): void {
const newCounter = storage.getPrimitive<i32>("counter", 0) + value;
storage.set<i32>("counter", newCounter);
logging.log("Counter is now: " + newCounter.toString());
}
export function decrementCounter(value: i32): void {
const newCounter = storage.getPrimitive<i32>("counter", 0) - value;
storage.set<i32>("counter", newCounter);
logging.log("Counter is now: " + newCounter.toString());
}
export function getCounter(): i32 {
return storage.getPrimitive<i32>("counter", 0);
}
export function resetCounter(): void {
storage.set<i32>("counter", 0);
logging.log("Counter is reset!");
}
Modify Test
- Modify
example.spec.ts
to reflect the code below
import {
getCounter,
resetCounter,
incrementCounter,
decrementCounter
} from '../index';
import { context, storage, VM } from 'near-sdk-as';
describe("Counter ", () => {
it("should increment by one", () => {
incrementCounter(1);
expect(getCounter()).toBe(1, "counter should be one after a single increment.");
});
it("getCounter is the same as reading from storage", () => {
expect(storage.getPrimitive<i32>("counter", 0)).toBe(getCounter(), "storage.getPrimitive<i32>(\"counter\", 0) = getCounter()");
});
it("should decrement by one", () => {
incrementCounter(1);
decrementCounter(1);
expect(getCounter()).toBe(0, "counter should be zero after a single decrement.");
});
it("should be resetable", () => {
incrementCounter(1);
incrementCounter(1);
resetCounter(); // reset to zero
expect(getCounter()).toBe(0, "counter should be zero after it is reset.");
});
it("should increment multiple times and decrement back to zero", () => {
incrementCounter(1);
expect(getCounter()).toBe(1, "0 + 1 = 1");
incrementCounter(3);
expect(getCounter()).toBe(4, "1 + 3 = 4");
decrementCounter(4);
expect(getCounter()).toBe(0, "4 - 4 = 0");
});
it("should be eve's account", () => {
expect(context.contractName).toBe("eve");
});
});
AssemblyScript Installation
- Execute the command below to install
AssemblyScript
loadernpm install --save @assemblyscript/loader
- Execute the command below to install
AssemblyScript
compilernpm install --save-dev assemblyscript
- Execute the command below to compile your project to WebAssembly
yarn asb
Test Project
- Execute the command below to import all npm dependencies
yarn install
- Execute the command below to ensure the project build properly
yarn build
- Execute the command below to verify that tests are not passing.
yarn test
Modify Tests to Pass
- Modify the import statement to ensure
VMCounter
is included fromnear-sdk-as
.
import { ..., VMContext, ... } from 'near-sdk-as'
- Modify the test to leverage
VMContext
to set an expected account id
it("should be eve's account", () => {
VMContext.setCurrent_account_id("eve");
expect(context.contractName, "eve");
})
- Execute the command below to verify that tests are passing.
yarn asp
Import Bind Gen Decorator
- Execute the command below from the root directory of the project to bootstrap global types
echo "/// <reference types=\"near-sdk-as/assembly/as_types\" />" > ./assembly/as_types.d.ts
Troubleshooting
- Click here to view the troubleshooting page on this article