1 | ## Remix-Tests
|
2 | [![npm version](https://badge.fury.io/js/remix-tests.svg)](https://www.npmjs.com/package/remix-tests)
|
3 | [![npm](https://img.shields.io/npm/dt/remix-tests.svg?label=Total%20Downloads)](https://www.npmjs.com/package/remix-tests)
|
4 | [![npm](https://img.shields.io/npm/dw/remix-tests.svg)](https://www.npmjs.com/package/remix-tests)
|
5 | [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/ethereum/remix/tree/master/remix-tests)
|
6 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/ethereum/remix/issues)
|
7 |
|
8 |
|
9 | `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.
|
10 |
|
11 | ### Installation
|
12 | As a dev dependency:
|
13 |
|
14 | `npm install --save-dev remix-tests`
|
15 |
|
16 | As a global NPM module to use as CLI:
|
17 |
|
18 | `npm -g install remix-tests`
|
19 |
|
20 | ### Test structure
|
21 | remix-tests provides and injects a built-in assert library for testing purpose.
|
22 |
|
23 | #### Assert library
|
24 |
|
25 | | Available functions | Supported types |
|
26 | | ------------- | ------------- |
|
27 | | `Assert.ok()` | `bool` |
|
28 | | `Assert.equal()` | `uint`, `int`, `bool`, `address`, `bytes32`, `string` |
|
29 | | `Assert.notEqual()` | `uint`, `int`, `bool`, `address`, `bytes32`, `string` |
|
30 | | `Assert.greaterThan()` | `uint`, `int` |
|
31 | | `Assert.lesserThan()` | `uint`, `int` |
|
32 |
|
33 | #### Available special functions:
|
34 | Apart from above, library provides some special functions as:
|
35 |
|
36 | * `beforeEach()` - runs before each test
|
37 | * `beforeAll()` - runs before all tests
|
38 | * `afterEach()` - runs after each test
|
39 | * `afterAll()` - runs after all tests
|
40 |
|
41 |
|
42 | #### Use a different sender `msg.sender`
|
43 |
|
44 | It is quite common that a contract need to be tested in different situation.
|
45 | 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.
|
46 | please checkout this [test contract](https://github.com/ethereum/remix/blob/master/remix-tests/tests/various_sender/sender_test.sol) for an example.
|
47 | Note that `TestsAccounts` is filled with all the accounts available in `web3.eth.accounts()`.
|
48 |
|
49 | ### How to use
|
50 |
|
51 | #### As command line interface
|
52 |
|
53 | * To run all files inside `examples` directory
|
54 | ```
|
55 | $ remix-tests examples/
|
56 | ```
|
57 | * To run single test file named `simple_storage_test.sol` inside `examples` directory
|
58 | ```
|
59 | $ remix-tests examples/simple_storage_test.sol
|
60 | ```
|
61 | **NOTE:** remix-tests will assume that name of tests file ends with `"_test.sol"`. e.g `simple_storage_test.sol`
|
62 |
|
63 |
|
64 | **Example:**
|
65 | Consider for a simple storage contract named `simple_storage.sol`:
|
66 |
|
67 | ```Javascript
|
68 | pragma solidity >=0.4.22 <0.7.0;
|
69 |
|
70 | contract SimpleStorage {
|
71 | uint public storedData;
|
72 |
|
73 | constructor() public {
|
74 | storedData = 100;
|
75 | }
|
76 |
|
77 | function set(uint x) public {
|
78 | storedData = x;
|
79 | }
|
80 |
|
81 | function get() public view returns (uint retVal) {
|
82 | return storedData;
|
83 | }
|
84 | }
|
85 | ```
|
86 |
|
87 | test file `simple_storage_test.sol` can be as:
|
88 |
|
89 |
|
90 | ```Javascript
|
91 | pragma solidity >=0.4.22 <0.7.0;
|
92 | import "remix_tests.sol"; // injected by remix-tests
|
93 | import "./simple_storage.sol";
|
94 |
|
95 | contract MyTest {
|
96 | SimpleStorage foo;
|
97 |
|
98 | function beforeEach() public {
|
99 | foo = new SimpleStorage();
|
100 | }
|
101 |
|
102 | function initialValueShouldBe100() public returns (bool) {
|
103 | return Assert.equal(foo.get(), 100, "initial value is not correct");
|
104 | }
|
105 |
|
106 | function valueIsSet200() public returns (bool) {
|
107 | foo.set(200);
|
108 | return Assert.equal(foo.get(), 200, "value is not 200");
|
109 | }
|
110 |
|
111 | function valueIsNotSet200() public returns (bool) {
|
112 | return Assert.notEqual(foo.get(), 200, "value is 200");
|
113 | }
|
114 | }
|
115 | ```
|
116 |
|
117 | Running `simple_storage_test.sol` file will output as:
|
118 |
|
119 | ```
|
120 | ◼ MyTest
|
121 | [19:15:02] payload method is eth_gasPrice
|
122 | [19:15:02] payload method is eth_sendTransaction
|
123 | [19:15:02] payload method is eth_getTransactionReceipt
|
124 | [19:15:02] payload method is eth_gasPrice
|
125 | [19:15:02] payload method is eth_sendTransaction
|
126 | [19:15:02] payload method is eth_getTransactionReceipt
|
127 | ✓ Initial value should be100
|
128 | [19:15:02] payload method is eth_gasPrice
|
129 | [19:15:02] payload method is eth_sendTransaction
|
130 | [19:15:02] payload method is eth_getTransactionReceipt
|
131 | [19:15:02] payload method is eth_gasPrice
|
132 | [19:15:02] payload method is eth_sendTransaction
|
133 | [19:15:02] payload method is eth_getTransactionReceipt
|
134 | ✓ Value is set200
|
135 | [19:15:02] payload method is eth_gasPrice
|
136 | [19:15:02] payload method is eth_sendTransaction
|
137 | [19:15:02] payload method is eth_getTransactionReceipt
|
138 | [19:15:02] payload method is eth_gasPrice
|
139 | [19:15:02] payload method is eth_sendTransaction
|
140 | [19:15:02] payload method is eth_getTransactionReceipt
|
141 | ✓ Value is not set200
|
142 | ```
|
143 |
|
144 | :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)
|
145 |
|
146 | #### As a Library for development
|
147 |
|
148 | Import library:
|
149 | ```Javascript
|
150 | const RemixTests = require('remix-tests');
|
151 | ```
|
152 |
|
153 | Run a single test object:
|
154 | ```Javascript
|
155 | remixTests.runTest (testName: string, testObject: any, contractDetails: CompiledContract, fileAST: AstNode, opts: Options, testCallback: TestCbInterface, resultsCallback: ResultCbInterface)
|
156 | ```
|
157 | <em>Params:-</em>
|
158 | 1. `testName` - Name of the test
|
159 | 2. `testObject` - Web3 1.0 contract instance of the test
|
160 | 3. `contractDetails` - Contract details
|
161 | 4. `fileAST` - AST of test file
|
162 | 5. `opts` - Custom options
|
163 | 6. `testCallback(object)` - Called each time there is a test event. 3 possible type of objects:
|
164 | * `{ type: 'contract', value: '<TestName>', filename: '<test_filename.sol>' }`
|
165 | * `{ type: 'testPass', value: '<name of testing function>', time: <time taken>, context: '<TestName>'}`
|
166 | * `{ type: 'testFailure', value: '<name of testing function>', time: <time taken>, context: '<TestName>', errMsg: '<message in the Assert>' }`
|
167 |
|
168 | 7. `resultsCallback(object)` - Callback with test results
|
169 | * `passingNum` - number of passing tests
|
170 | * `failureNum` - number of failing tests
|
171 | * `timePassed` - time it took for all the tests to run (in seconds)
|
172 |
|
173 | Running a set of tests given the sourcecode:
|
174 | ```Javascript
|
175 | remixTests.runTestSources(contractSources: SrcIfc, versionUrl: string, usingWorker: boolean, testCallback: Function, resultCallback: Function, finalCallback: any, importFileCb: Function, opts: Options);
|
176 | ```
|
177 | <em>Params:-</em>
|
178 | 1. `contractSources` - Contract sources
|
179 | 2. `versionUrl` - URL of solc compiler to load
|
180 | 3. `usingWorker` - Set `true` if compiler should be loaded using web-worker
|
181 | 4. `testCallback(object)` - Called each time there is a test event. 3 possible type of objects:
|
182 | * `{ type: 'contract', value: '<TestName>', filename: '<test_filename.sol>' }`
|
183 | * `{ type: 'testPass', value: '<name of testing function>', time: <time taken>, context: '<TestName>'}`
|
184 | * `{ type: 'testFailure', value: '<name of testing function>', time: <time taken>, context: '<TestName>', errMsg: '<message in the Assert>' }`
|
185 |
|
186 | 5. `resultCallback(err, object)` - Callback with test results
|
187 | * `passingNum` - number of passing tests
|
188 | * `failureNum` - number of failing tests
|
189 | * `timePassed` - time it took for all the tests to run (in seconds)
|
190 |
|
191 | 6. `finalCallback(err)` - called when all tests finish running.
|
192 | 7. `importCb(url, cb)` - Callback to resolve imported files
|
193 | 8. `opts` - Custom options
|
194 |
|
195 | For more details, see parameters' type definitions [here](https://github.com/ethereum/remix/blob/master/remix-tests/src/types.ts).
|
196 |
|
197 | ## Contribute
|
198 |
|
199 | Please feel free to open an issue or a pull request.
|
200 |
|
201 | In case you want to add a code, do have a look to our contribution guidelnes [here](https://github.com/ethereum/remix/blob/master/CONTRIBUTING.md). Reach us in [Gitter](https://gitter.im/ethereum/remix) in case of any queries.
|
202 |
|
203 | ## License
|
204 |
|
205 | [MIT](LICENSE.md) © 2018 Remix Team
|