Contract Shark is a framework for testing smart contracts written in Solidity. By framework we mean a library with some conveniences.
Contract Shark provides development environment for the Ethereum blockchain and includes useful tools which enable developers to easily write tests for smart contracts.
The source code is available on GitHub where you can also find our issue tracker.
Start by installing the contract-shark command-line tool.
$ npm install -g @contractshark/cli web3 solc
contract-shark depends on the latest web3 and solc packages, so make sure you have them globally installed. contract-shark also uses promises thus you need to use Promise polyfill when promises are not supported.
contract-shark automates the testing process of your Solidity code. It doesn’t require you to install certain applications in order to get started.
$ mkdir -p ${project_name}
$ cd ${project_name}
$ contractshark init
$ npm install
$ npm test
The core test functionality is provided by the @contractshark/spec
module which is automatically attached to your project at initialization. Here we explain some of the main framework features but please explore the source code to find out all the possibilities.
The framework provides a Spec
class which holds basically the whole testing power. You start your test by creating an instance of that class.
import { Spec } from "@contractshark/spec";
const spec = new Spec();
The Spec instance provides methods that you can use when writing tests. Most of the time you will use the test
method which performs the test you write.
spec.test("is true", async (ctx) => {
// promise | function
ctx.true(true);
});
There is also the skip
method which prevents a test to be performed, and the only
method which includes itself into the test process but excludes all other tests.
Tests can be nested using the spec
method.
const colors = new Spec();
...
spec.spec('colors', colors);
The framework provides before
and after
methods which are execute at the beginning and at the end of the spec case.
spec.before((stage) => {
// execute before all tests
});
...
spec.after((stage) => {
// execute after all tests
});
These methods have access to the stage
of the spec instance. The stage is global to the whole spec stack which means that all settings are always preserved.
There are also the beforeEach
and afterEach
methods which are triggered before and after each test. These methods have access to the context
and stage
of the spec. The context represents a copy of a stage and is preserved between beforeEach
, test
and afterEach
methods. This allows for testing atomic tests where a fresh context is always created for each test.
spec.beforeEach((context, stage) => {
// execute before all tests
});
...
spec.afterEach((context, stage) => {
// execute after all tests
});
Callback functions can be called multiple times and the execution will happen in a defined sequence.
The context
and the stage
both provide a way to set
and get
values with proper TypeScript types.
interface Data {
id: number;
name: string;
}
const spec = new Spec<Data>();
spec.beforeEach((ctx) => {
ctx.set("id", 100);
ctx.set("name", "John");
});
spec.test("is John with id=100", (ctx) => {
const id = ctx.get("id");
const name = ctx.get("name");
ctx.is(id, 100);
ctx.is(name, "John");
});
Values set inside the before
and after
blocks are available to all spec
methods. Values set in the beforeEach
and afterEach
blocks are available only on the context stack of each test.
Stage and context both provide a series of different helper methods.
A very important method is the deploy()
method which deploys a contract to a local blockchain process in the background and returns a contract instance.
const { instance, receipt } = await ctx.deploy({
src: "./contracts.json",
contract: "Main",
});
The @contractshark/cli
module is automatically installed when you initialize the project. You can interact with the utility using the npx contract-shark
command in your terminal.
To get a list of available features use the --help
flag.
$ npx contractshark --help
Every test file must export the spec
instance for the CLI to be able to detect the test.
export default spec;
Run the contract-shark test
command to run tests. Customize the files search by using the --match
flag.
$ npx contract-shark test --match ./**/*.test.*
Install the ts-node NPM package then use the --require
flag to enable TypeScript support.
contract-shark --require ts-node/register
contract-shark configuration options can be saved inside the package.json file under the the contract-shark
key.
{
"contract-shark": {
"compiler": {
"build": "./build",
"match": ["./src/**/*.sol"],
"severities": ["error", "warning"],
"evmVersion": "byzantium"
},
"flattener": {
"build": "./build",
"match": ["./src/**/*.sol"],
"severities": ["error", "warning"]
},
"sandbox": {
"port": 8545,
"host": "localhost"
},
"test": {
"server": true,
"port": 8545,
"host": "localhost",
"match": ["./src/**/*.test.*"]
},
"require": ["ts-node/register"]
}
}
Note that these options can be overriden by providing CLI arguments.
For a full example of a Solidity contract repository including continuous integration using Travis and contract-shark, see [URL]
Package | Description | Version |
---|---|---|
@contractshark/cli | Command-line interface. | |
@contractshark/compiler | Smart contracts compiler. | |
@contractshark/flattener | Smart contracts flattener. | |
@contractshark/init | Project structure initializer. | |
@contractshark/sandbox | Ethereum sandbox server. | |
@contractshark/spec | Core test suite. |
@contract-shark/spec
See CONTRIBUTING.md for how to help out.
See LICENSE for details.