## Remix-Tests [![npm version](https://badge.fury.io/js/%40remix-project%2Fremix-tests.svg)](https://www.npmjs.com/package/@remix-project/remix-tests) [![npm](https://img.shields.io/npm/dt/@remix-project/remix-tests.svg?label=Total%20Downloads)](https://www.npmjs.com/package/@remix-project/remix-tests) [![npm](https://img.shields.io/npm/dw/@remix-project/remix-tests.svg)](https://www.npmjs.com/package/@remix-project/remix-tests) [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/ethereum/remix-project/tree/master/libs/remix-tests) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/ethereum/remix-project/issues) `remix-tests` is a tool to test Solidity smart contracts. It works underneath Remix IDE plugin "Solidity Unit Testing" which is used to write and run test cases for a contract. Tests are written in Solidity itself. `remix-tests` can be used as CLI and a library too. To know more about Remix IDE `Solidity Unit Testing Plugin`, visit [Remix IDE official documentation](https://remix-ide.readthedocs.io/en/latest/unittesting.html). ### Installation * As a dev dependency: `npm install --save-dev @remix-project/remix-tests` * As a global NPM module to use as CLI: `npm -g install @remix-project/remix-tests` To confirm installation, run: ``` $ remix-tests --version 0.1.34 ``` Version should be same as on NPM. ### Test structure remix-tests provides and injects a built-in assert library for testing purpose. #### Assert library | Available functions | Supported types | | ------------- | ------------- | | `Assert.ok()` | `bool` | | `Assert.equal()` | `uint`, `int`, `bool`, `address`, `bytes32`, `string` | | `Assert.notEqual()` | `uint`, `int`, `bool`, `address`, `bytes32`, `string` | | `Assert.greaterThan()` | `uint`, `int` | | `Assert.lesserThan()` | `uint`, `int` | Examples to understand the use of assert library methods can be found [here in tests](tests/examples_0). #### Available special functions: Apart from above, library provides some special functions as: * `beforeEach()` - runs before each test * `beforeAll()` - runs before all tests * `afterEach()` - runs after each test * `afterAll()` - runs after all tests Example to understand the use of special methods can be found [here in tests](tests/various_sender/sender_and_value_test.sol). #### Use a different sender `msg.sender` It is quite common that a contract need to be tested in different situation. Especially being able to set before hand the sender account (`msg.sender`) used for a specific tests suite enable quite a lot a new test use cases. please checkout this [test contract](tests/various_sender/sender_and_value_test.sol) for an example. Note that `TestsAccounts` is filled with all the accounts available in `web3.eth.accounts()`. ### How to use #### As command line interface * To run all test files inside `examples` directory ``` $ remix-tests examples/ ``` * To run single test file named `simple_storage_test.sol` inside `examples` directory ``` $ remix-tests examples/simple_storage_test.sol ``` **NOTE:** remix-tests will assume that name of tests file ends with `"_test.sol"`. e.g `simple_storage_test.sol` **Example:** Consider for a simple storage contract named `simple_storage.sol`: ```Javascript pragma solidity >=0.4.22 <0.7.0; contract SimpleStorage { uint public storedData; constructor() public { storedData = 100; } function set(uint x) public { storedData = x; } function get() public view returns (uint retVal) { return storedData; } } ``` test file `simple_storage_test.sol` can be as: ```Javascript pragma solidity >=0.4.22 <0.7.0; import "remix_tests.sol"; // injected by remix-tests import "./simple_storage.sol"; contract MyTest { SimpleStorage foo; function beforeEach() public { foo = new SimpleStorage(); } function initialValueShouldBe100() public returns (bool) { return Assert.equal(foo.get(), 100, "initial value is not correct"); } function valueIsSet200() public returns (bool) { foo.set(200); return Assert.equal(foo.get(), 200, "value is not 200"); } function valueIsNotSet200() public returns (bool) { return Assert.notEqual(foo.get(), 200, "value is 200"); } } ``` Running `simple_storage_test.sol` file will output as: ``` 👁 :: Running remix-tests - Unit testing for solidity :: 👁 [14:58:43] payload method is eth_accounts [14:58:49] payload method is eth_accounts [14:58:49] payload method is eth_estimateGas [14:58:49] payload method is eth_gasPrice [14:58:49] payload method is eth_sendTransaction [14:58:49] payload method is eth_getTransactionReceipt [14:58:49] payload method is eth_getCode 'creation of library remix_tests.sol:Assert pending...' [14:58:49] payload method is eth_estimateGas [14:58:49] payload method is eth_gasPrice [14:58:49] payload method is eth_sendTransaction [14:58:49] payload method is eth_getTransactionReceipt [14:58:49] payload method is eth_getCode [14:58:49] payload method is eth_estimateGas [14:58:49] payload method is eth_gasPrice [14:58:49] payload method is eth_sendTransaction [14:58:49] payload method is eth_getTransactionReceipt [14:58:49] payload method is eth_getCode ◼ MyTest [14:58:49] payload method is eth_gasPrice [14:58:49] payload method is eth_sendTransaction [14:58:50] payload method is eth_getTransactionReceipt [14:58:50] payload method is eth_gasPrice [14:58:50] payload method is eth_sendTransaction [14:58:50] payload method is eth_getTransactionReceipt ✓ Initial value should be100 [14:58:50] payload method is eth_gasPrice [14:58:50] payload method is eth_sendTransaction [14:58:50] payload method is eth_getTransactionReceipt [14:58:50] payload method is eth_gasPrice [14:58:50] payload method is eth_sendTransaction [14:58:50] payload method is eth_getTransactionReceipt ✓ Value is set200 [14:58:50] payload method is eth_gasPrice [14:58:50] payload method is eth_sendTransaction [14:58:50] payload method is eth_getTransactionReceipt [14:58:50] payload method is eth_gasPrice [14:58:50] payload method is eth_sendTransaction [14:58:50] payload method is eth_getTransactionReceipt ✓ Value is not set200 3 passing (0s) ``` :point_right: remix-test can also be used for continuous integration testing. See example [Su Squares contract](https://github.com/su-squares/ethereum-contract/tree/e542f37d4f8f6c7b07d90a6554424268384a4186) and [Travis build](https://travis-ci.org/su-squares/ethereum-contract/builds/446186067) #### As a Library for development Import library: ```Javascript const remixTests = require('@remix-project/remix-tests'); ``` Run a single test object: ```Javascript remixTests.runTest (testName: string, testObject: any, contractDetails: CompiledContract, fileAST: AstNode, opts: Options, testCallback: TestCbInterface, resultsCallback: ResultCbInterface) ``` Params:- 1. `testName` - Name of the test 2. `testObject` - Web3 1.0 contract instance of the test 3. `contractDetails` - Contract details 4. `fileAST` - AST of test file 5. `opts` - Custom options 6. `testCallback(object)` - Called each time there is a test event. 3 possible type of objects: * `{ type: 'contract', value: '', filename: '' }` * `{ type: 'testPass', value: '', time: