UNPKG

6.06 kBPlain TextView Raw
1import async from 'async'
2import fs from './fileSystem'
3import { runTest } from './testRunner'
4import { TestResultInterface, ResultsInterface, compilationInterface, ASTInterface, Options, AstNode } from './types'
5import colors from 'colors'
6import Web3 from 'web3';
7
8import { compileFileOrFiles } from './compiler'
9import { deployAll } from './deployer'
10
11/**
12 * @dev run test contract files (used for CLI)
13 * @param filepath Path of file
14 * @param isDirectory True, if path is a directory
15 * @param web3 Web3
16 * @param finalCallback optional callback to run finally
17 * @param opts Options
18 */
19
20export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3, finalCallback: any = () => {}, opts?: Options) {
21 opts = opts || {}
22 const sourceASTs: any = {}
23 const { Signale } = require('signale')
24 // signale configuration
25 const options = {
26 types: {
27 result: {
28 badge: '\t✓',
29 label: '',
30 color: 'greenBright'
31 },
32 name: {
33 badge: '\n\t◼',
34 label: '',
35 color: 'white'
36 },
37 error: {
38 badge: '\t✘',
39 label: '',
40 color: 'redBright'
41 }
42 }
43 }
44 const signale = new Signale(options)
45 let accounts = opts['accounts'] || null
46 async.waterfall([
47 function getAccountList (next: Function) {
48 if (accounts) return next(null)
49 web3.eth.getAccounts((_err: Error | null | undefined, _accounts) => {
50 accounts = _accounts
51 next(null)
52 })
53 },
54 function compile(next: Function) {
55 compileFileOrFiles(filepath, isDirectory, { accounts }, next)
56 },
57 function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next: Function) {
58 // Extract AST of test contract file source
59 for(const filename in asts) {
60 if(filename.endsWith('_test.sol'))
61 sourceASTs[filename] = asts[filename].ast
62 }
63 deployAll(compilationResult, web3, false, (err, contracts) => {
64 if (err) {
65 next(err)
66 }
67 next(null, compilationResult, contracts)
68 })
69 },
70 function determineTestContractsToRun (compilationResult: compilationInterface, contracts: any, next: Function) {
71 let contractsToTest: string[] = []
72 let contractsToTestDetails: any[] = []
73 const gatherContractsFrom = function(filename: string) {
74 if (!filename.endsWith('_test.sol')) {
75 return
76 }
77 try {
78 Object.keys(compilationResult[filename]).forEach(contractName => {
79 contractsToTest.push(contractName)
80 contractsToTestDetails.push(compilationResult[filename][contractName])
81 })
82 } catch (e) {
83 console.error(e)
84 }
85 }
86 if (isDirectory) {
87 fs.walkSync(filepath, (foundpath: string) => {
88 gatherContractsFrom(foundpath)
89 })
90 } else {
91 gatherContractsFrom(filepath)
92 }
93 next(null, contractsToTest, contractsToTestDetails, contracts)
94 },
95 function runTests(contractsToTest: string[], contractsToTestDetails: any[], contracts: any, next: Function) {
96 let totalPassing: number = 0
97 let totalFailing: number = 0
98 let totalTime: number = 0
99 let errors: any[] = []
100
101 const _testCallback = function (err: Error | null | undefined, result: TestResultInterface) {
102 if(err) throw err;
103 if (result.type === 'contract') {
104 signale.name(result.value.white)
105 } else if (result.type === 'testPass') {
106 signale.result(result.value)
107 } else if (result.type === 'testFailure') {
108 signale.result(result.value.red)
109 errors.push(result)
110 }
111 }
112 const _resultsCallback = (_err: Error | null | undefined, result: ResultsInterface, cb) => {
113 totalPassing += result.passingNum
114 totalFailing += result.failureNum
115 totalTime += result.timePassed
116 cb()
117 }
118
119 async.eachOfLimit(contractsToTest, 1, (contractName: string, index, cb) => {
120 try {
121 const fileAST: AstNode = sourceASTs[contracts[contractName]['filename']]
122 runTest(contractName, contracts[contractName], contractsToTestDetails[index], fileAST, { accounts }, _testCallback, (err, result) => {
123 if (err) {
124 console.log(err)
125 return cb(err)
126 }
127 _resultsCallback(null, result, cb)
128 })
129 } catch(e) {
130 console.error(e)
131 }
132 }, function (err) {
133 if (err) {
134 return next(err)
135 }
136
137 console.log('\n')
138 if (totalPassing > 0) {
139 console.log(colors.green(totalPassing + ' passing ') + colors.grey('(' + totalTime + 's)'))
140 }
141 if (totalFailing > 0) {
142 console.log(colors.red(totalFailing + ' failing'))
143 }
144 console.log('')
145
146 errors.forEach((error, index) => {
147 console.log(' ' + (index + 1) + ') ' + error.context + ' ' + error.value)
148 console.log('')
149 console.log(colors.red('\t error: ' + error.errMsg))
150 })
151 console.log('')
152
153 next()
154 })
155 }
156 ], finalCallback)
157}