itee-tasks 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.czrc +6 -0
- package/.github/workflows/node.js.yml +56 -0
- package/.releaserc.mjs +94 -0
- package/CHANGELOG.md +25 -0
- package/README.md +1 -0
- package/configs/builds/build.conf.mjs +1 -0
- package/configs/cleans/clean.conf.mjs +1 -0
- package/configs/docs/doc.conf.json +1 -0
- package/configs/lints/lint.conf.mjs +91 -0
- package/configs/refresh.conf.mjs +1 -0
- package/configs/tests/benchmarks/compute-benchmarks.conf.mjs +25 -0
- package/configs/tests/benchmarks/run-benchmarks-for-frontend.conf.mjs +41 -0
- package/configs/tests/benchmarks/run-benchmarks.conf.mjs +7 -0
- package/configs/tests/bundlings/check-bundling-from-esm-build-import.conf.mjs +45 -0
- package/configs/tests/bundlings/check-bundling-from-esm-files-direct.conf.mjs +45 -0
- package/configs/tests/bundlings/check-bundling-from-esm-files-import.conf.mjs +42 -0
- package/configs/tests/bundlings/check-bundling.conf.mjs +25 -0
- package/configs/tests/units/compute-unit-tests.conf.mjs +25 -0
- package/configs/tests/units/run-unit-tests-for-frontend.conf.mjs +15 -0
- package/configs/tests/units/run-unit-tests.conf.mjs +7 -0
- package/gulpfile.mjs +28 -0
- package/package.json +91 -0
- package/sources/_utils.mjs +389 -0
- package/sources/builds/build.task.mjs +55 -0
- package/sources/cleans/clean.task.mjs +36 -0
- package/sources/docs/doc.task.mjs +49 -0
- package/sources/helps/help.task.mjs +154 -0
- package/sources/index.mjs +21 -0
- package/sources/lints/lint.task.mjs +47 -0
- package/sources/refresh.mjs +100 -0
- package/sources/releases/release.task.mjs +31 -0
- package/sources/tests/benchmarks/compute-benchmarks.task.mjs +224 -0
- package/sources/tests/benchmarks/run-benchmarks-for-backend.task.mjs +42 -0
- package/sources/tests/benchmarks/run-benchmarks-for-frontend.task.mjs +52 -0
- package/sources/tests/benchmarks/run-benchmarks.task.mjs +21 -0
- package/sources/tests/bundlings/check-bundling-from-esm-build-import.task.mjs +131 -0
- package/sources/tests/bundlings/check-bundling-from-esm-files-direct.task.mjs +88 -0
- package/sources/tests/bundlings/check-bundling-from-esm-files-import.task.mjs +106 -0
- package/sources/tests/bundlings/check-bundling.task.mjs +23 -0
- package/sources/tests/run-tests.task.mjs +21 -0
- package/sources/tests/units/compute-unit-tests.task.mjs +535 -0
- package/sources/tests/units/run-unit-tests-for-backend.task.mjs +47 -0
- package/sources/tests/units/run-unit-tests-for-frontend.task.mjs +52 -0
- package/sources/tests/units/run-unit-tests.task.mjs +21 -0
- package/tests/benchmarks/default/default.bench.js +1 -0
- package/tests/benchmarks/itee-tasks.benchmarks.js +8 -0
- package/tests/units/default/default.unit.mjs +1 -0
- package/tests/units/itee-tasks.units.mjs +1 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
import colors from 'ansi-colors'
|
|
2
|
+
import childProcess from 'child_process'
|
|
3
|
+
import log from 'fancy-log'
|
|
4
|
+
import { isNotEmptyArray } from 'itee-validators'
|
|
5
|
+
import {
|
|
6
|
+
basename,
|
|
7
|
+
dirname,
|
|
8
|
+
extname,
|
|
9
|
+
join,
|
|
10
|
+
relative
|
|
11
|
+
} from 'path'
|
|
12
|
+
import {
|
|
13
|
+
createDirectoryIfNotExist,
|
|
14
|
+
createFile,
|
|
15
|
+
getConfigurationFrom,
|
|
16
|
+
getConfigurationPathFor,
|
|
17
|
+
getPrettyPackageName,
|
|
18
|
+
Indenter,
|
|
19
|
+
logLoadingTask,
|
|
20
|
+
packageName,
|
|
21
|
+
packageNodeModulesDirectory,
|
|
22
|
+
packageSourcesDirectory as sourcesDir,
|
|
23
|
+
packageTestsUnitsDirectory as unitsDir
|
|
24
|
+
} from '../../_utils.mjs'
|
|
25
|
+
|
|
26
|
+
const configurationLocation = join( 'tests', 'units', 'compute-unit-tests.conf.mjs' )
|
|
27
|
+
const configurationPath = getConfigurationPathFor( configurationLocation )
|
|
28
|
+
const configuration = await getConfigurationFrom( configurationPath )
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
red,
|
|
32
|
+
yellow,
|
|
33
|
+
} = colors
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @description Will generate unit test files from source code using type inference from comments
|
|
37
|
+
*/
|
|
38
|
+
const computeUnitTestsTask = ( done ) => {
|
|
39
|
+
|
|
40
|
+
createDirectoryIfNotExist( unitsDir )
|
|
41
|
+
|
|
42
|
+
const unitsImportMap = []
|
|
43
|
+
for ( let sourceFile of configuration ) {
|
|
44
|
+
|
|
45
|
+
const specificFilePath = sourceFile.replace( sourcesDir, '' )
|
|
46
|
+
const specificDir = dirname( specificFilePath )
|
|
47
|
+
|
|
48
|
+
const fileName = basename( sourceFile, extname( sourceFile ) )
|
|
49
|
+
const unitFileName = `${ fileName }.unit.mjs`
|
|
50
|
+
const unitDirPath = join( unitsDir, specificDir )
|
|
51
|
+
const unitFilePath = join( unitDirPath, unitFileName )
|
|
52
|
+
|
|
53
|
+
const nsName = `${ fileName }Namespace`
|
|
54
|
+
const unitName = `${ fileName }Units`
|
|
55
|
+
const importDirPath = relative( unitDirPath, sourcesDir )
|
|
56
|
+
const importFilePath = join( importDirPath, specificFilePath ).replace( /\\/g, '/' )
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
|
|
60
|
+
const jsdocPath = join( packageNodeModulesDirectory, '/jsdoc/jsdoc.js' )
|
|
61
|
+
const jsdocOutput = childProcess.execFileSync( 'node', [ jsdocPath, '-X', sourceFile ] ).toString()
|
|
62
|
+
|
|
63
|
+
const classNames = []
|
|
64
|
+
const usedLongnames = []
|
|
65
|
+
const jsonData = JSON.parse( jsdocOutput ).filter( data => {
|
|
66
|
+
|
|
67
|
+
const longName = data.longname
|
|
68
|
+
|
|
69
|
+
const kind = data.kind
|
|
70
|
+
if ( kind !== 'function' ) {
|
|
71
|
+
if ( kind === 'class' && !classNames.includes( longName ) ) {
|
|
72
|
+
classNames.push( longName )
|
|
73
|
+
}
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const undocumented = data.undocumented
|
|
78
|
+
if ( undocumented ) {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const scope = data.scope
|
|
83
|
+
if ( ![ 'global', 'static' ].includes( scope ) ) {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if ( longName.includes( ' ' ) || longName.includes( '~' ) || usedLongnames.includes( longName ) ) {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for ( let className of classNames ) {
|
|
92
|
+
if ( longName.includes( className ) ) {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
usedLongnames.push( longName )
|
|
98
|
+
|
|
99
|
+
return true
|
|
100
|
+
|
|
101
|
+
} )
|
|
102
|
+
|
|
103
|
+
if ( jsonData.length === 0 ) {
|
|
104
|
+
log( 'Ignoring', yellow( `${ sourceFile }, no usable exports found` ) )
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let describes = ''
|
|
109
|
+
const {
|
|
110
|
+
I,
|
|
111
|
+
I_,
|
|
112
|
+
I__,
|
|
113
|
+
I___,
|
|
114
|
+
} = new Indenter( '\t', 3 )
|
|
115
|
+
|
|
116
|
+
for ( let docData of jsonData ) {
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
|
|
120
|
+
//check input parameters and types
|
|
121
|
+
const docParameters = docData.params || []
|
|
122
|
+
const parameters = []
|
|
123
|
+
for ( let pIndex = 0 ; pIndex < docParameters.length ; pIndex++ ) {
|
|
124
|
+
const param = docParameters[ pIndex ]
|
|
125
|
+
let paramName = param.name
|
|
126
|
+
if ( !paramName ) {
|
|
127
|
+
paramName = `param${ pIndex }`
|
|
128
|
+
log( yellow( `Missing parameter name for [${ docData.longname }]. Defaulting to [${ paramName }]` ) )
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const paramType = param.type
|
|
132
|
+
if ( !paramType ) {
|
|
133
|
+
throw new ReferenceError( `Missing parameter type. Unable to create unit test for [${ docData.longname }] !` )
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const parameter = {
|
|
137
|
+
name: paramName,
|
|
138
|
+
types: []
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const paramTypeNames = paramType.names
|
|
142
|
+
for ( let type of paramTypeNames ) {
|
|
143
|
+
parameter.types.push( type )
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
parameters.push( parameter )
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check returns types
|
|
150
|
+
const docReturns = docData.returns || []
|
|
151
|
+
const returns = []
|
|
152
|
+
for ( let docReturn of docReturns ) {
|
|
153
|
+
const returnType = docReturn.type
|
|
154
|
+
if ( !returnType ) {
|
|
155
|
+
throw new ReferenceError( `Missing return type for [${ docData.longname }]. Ignore current target !` )
|
|
156
|
+
}
|
|
157
|
+
returns.push( ...returnType.names )
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Todo check throws
|
|
161
|
+
|
|
162
|
+
// Get user define rules
|
|
163
|
+
// const rules = []
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
// Infer basic rules
|
|
167
|
+
const baseIndent = 2
|
|
168
|
+
let its = ''
|
|
169
|
+
|
|
170
|
+
if ( parameters.length === 0 ) {
|
|
171
|
+
|
|
172
|
+
if ( returns.length === 0 ) {
|
|
173
|
+
|
|
174
|
+
const result = `${ I._( baseIndent + 1 ) }const result = ${ nsName }.${ docData.name }()` + '\n'
|
|
175
|
+
const expect = `${ I._( baseIndent + 1 ) }expect(result).to.be.a('undefined')` + '\n'
|
|
176
|
+
|
|
177
|
+
its += '' +
|
|
178
|
+
`${ I._( baseIndent ) }it( 'should return undefined value on call', async function () {` + '\n' +
|
|
179
|
+
'\n' +
|
|
180
|
+
`${ result }` +
|
|
181
|
+
`${ expect }` +
|
|
182
|
+
'\n' +
|
|
183
|
+
`${ I._( baseIndent ) }} )` + '\n'
|
|
184
|
+
|
|
185
|
+
} else if ( returns.length === 1 ) {
|
|
186
|
+
|
|
187
|
+
const firstReturnType = returns[ 0 ]
|
|
188
|
+
const lowerName = firstReturnType.toLowerCase()
|
|
189
|
+
|
|
190
|
+
const result = `${ I._( baseIndent + 1 ) }const result = ${ nsName }.${ docData.name }()` + '\n'
|
|
191
|
+
|
|
192
|
+
let expect = ''
|
|
193
|
+
if ( lowerName.startsWith( 'array' ) ) {
|
|
194
|
+
//todo array of...
|
|
195
|
+
expect += `${ I._( baseIndent + 1 ) }expect(result).to.be.a('array')` + '\n'
|
|
196
|
+
} else {
|
|
197
|
+
expect += `${ I._( baseIndent + 1 ) }expect(result).to.be.a('${ lowerName }')` + '\n'
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
its += '' +
|
|
201
|
+
`${ I._( baseIndent ) }it( 'should return value of type ${ lowerName }', async function() {` + '\n' +
|
|
202
|
+
'\n' +
|
|
203
|
+
`${ result }` +
|
|
204
|
+
`${ expect }` +
|
|
205
|
+
'\n' +
|
|
206
|
+
`${ I._( baseIndent ) }} )` + '\n'
|
|
207
|
+
|
|
208
|
+
} else {
|
|
209
|
+
|
|
210
|
+
const result = `${ I._( baseIndent + 1 ) }const result = ${ nsName }.${ docData.name }()` + '\n'
|
|
211
|
+
|
|
212
|
+
let returnTypesLabel = []
|
|
213
|
+
let oneOf = []
|
|
214
|
+
for ( let returnType of returns ) {
|
|
215
|
+
|
|
216
|
+
const lowerName = returnType.toLowerCase()
|
|
217
|
+
returnTypesLabel.push( lowerName )
|
|
218
|
+
|
|
219
|
+
if ( lowerName.startsWith( 'array' ) ) {
|
|
220
|
+
//todo array of...
|
|
221
|
+
oneOf.push( 'array' )
|
|
222
|
+
} else {
|
|
223
|
+
oneOf.push( `'${ lowerName }'` )
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const underlyingType = `${ I._( baseIndent + 1 ) }const resultType = (result === null) ? 'null' : typeof result` + '\n'
|
|
229
|
+
const expect = `${ I._( baseIndent + 1 ) }expect(resultType).to.be.oneOf([${ oneOf.join( ',' ) }])` + '\n'
|
|
230
|
+
|
|
231
|
+
its += '' +
|
|
232
|
+
`${ I._( baseIndent ) }it( 'should return value where type is ${ returnTypesLabel.join( ' or ' ) }', async function() {` + '\n' +
|
|
233
|
+
'\n' +
|
|
234
|
+
`${ result }` +
|
|
235
|
+
`${ underlyingType }` +
|
|
236
|
+
`${ expect }` +
|
|
237
|
+
'\n' +
|
|
238
|
+
`${ I._( baseIndent ) }} )` + '\n'
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
} else {
|
|
243
|
+
|
|
244
|
+
if ( returns.length === 0 ) {
|
|
245
|
+
|
|
246
|
+
let itDeclaration = []
|
|
247
|
+
let index = 0
|
|
248
|
+
let indent = baseIndent + 1
|
|
249
|
+
let localIndent = indent
|
|
250
|
+
let dataSets = ''
|
|
251
|
+
let forLoopOpens = ''
|
|
252
|
+
let forLoopCloses = ''
|
|
253
|
+
let args = []
|
|
254
|
+
for ( let parameter of parameters ) {
|
|
255
|
+
|
|
256
|
+
const parameterType = parameter.types[ 0 ]
|
|
257
|
+
itDeclaration.push( `${ parameter.name } is of type ${ parameterType }` )
|
|
258
|
+
|
|
259
|
+
dataSets += `${ I._( indent ) }const dataSet${ index } = _dataMap[ '${ parameterType }s' ]` + '\n'
|
|
260
|
+
// dataSets += `${ I._( indent ) }const dataSet${ index } = this._dataMap[ '${ parameterType }s' ]` + '\n'
|
|
261
|
+
forLoopOpens += '' + '\n' +
|
|
262
|
+
`${ I._( localIndent ) }for ( let key${ index } in dataSet${ index } ) {` + '\n' +
|
|
263
|
+
`${ I._( localIndent + 1 ) }const dataSetValue${ index } = dataSet${ index }[ key${ index } ]` + '\n'
|
|
264
|
+
|
|
265
|
+
args.push( `dataSetValue${ index }` )
|
|
266
|
+
|
|
267
|
+
forLoopCloses = `${ I._( localIndent ) }}` + '\n' + `${ forLoopCloses }`
|
|
268
|
+
|
|
269
|
+
index++
|
|
270
|
+
localIndent++
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const result = `${ I._( localIndent ) }const result = ${ nsName }.${ docData.name }( ${ args.join( ', ' ) } )` + '\n'
|
|
274
|
+
const expect = `${ I._( localIndent ) }expect(result).to.be.a('undefined')` + '\n'
|
|
275
|
+
|
|
276
|
+
const param = '' +
|
|
277
|
+
`${ dataSets }` +
|
|
278
|
+
`${ forLoopOpens }` +
|
|
279
|
+
`${ result }` +
|
|
280
|
+
`${ expect }` +
|
|
281
|
+
`${ forLoopCloses }`
|
|
282
|
+
|
|
283
|
+
its += '' +
|
|
284
|
+
`${ I._( baseIndent ) }it( 'should return undefined value when ${ itDeclaration.join( ' and ' ) }', async function() {` + '\n' +
|
|
285
|
+
'\n' +
|
|
286
|
+
`${ param }` +
|
|
287
|
+
'\n' +
|
|
288
|
+
`${ I._( baseIndent ) }} )` + '\n'
|
|
289
|
+
|
|
290
|
+
} else if ( returns.length === 1 ) {
|
|
291
|
+
|
|
292
|
+
const firstReturnType = returns[ 0 ]
|
|
293
|
+
const lowerName = firstReturnType.toLowerCase()
|
|
294
|
+
|
|
295
|
+
let itDeclaration = []
|
|
296
|
+
let index = 0
|
|
297
|
+
let indent = baseIndent + 1
|
|
298
|
+
let localIndent = indent
|
|
299
|
+
let dataSets = ''
|
|
300
|
+
let forLoopOpens = ''
|
|
301
|
+
let forLoopCloses = ''
|
|
302
|
+
let args = []
|
|
303
|
+
for ( let parameter of parameters ) {
|
|
304
|
+
|
|
305
|
+
const parameterType = parameter.types[ 0 ]
|
|
306
|
+
const isAnyType = ( parameterType === '*' || parameterType.toLowerCase() === 'any' )
|
|
307
|
+
const declaration = ( isAnyType )
|
|
308
|
+
? `${ parameter.name } is of any type`
|
|
309
|
+
: `${ parameter.name } is of type ${ parameterType }`
|
|
310
|
+
itDeclaration.push( declaration )
|
|
311
|
+
|
|
312
|
+
if ( isAnyType ) {
|
|
313
|
+
|
|
314
|
+
dataSets += `${ I._( indent ) }const dataMap${ index } = _dataMap` + '\n' +
|
|
315
|
+
// dataSets += `${ I._( indent ) }const dataMap${ index } = this._dataMap` + '\n' +
|
|
316
|
+
`${ I._( localIndent ) }for ( let dataSetKey${ index } in dataMap${ index } ) {` + '\n'
|
|
317
|
+
|
|
318
|
+
localIndent++
|
|
319
|
+
dataSets += `${ I._( indent + 1 ) }const dataSet${ index } = dataMap${ index }[ dataSetKey${ index } ]` + '\n'
|
|
320
|
+
forLoopOpens += '' + '\n' +
|
|
321
|
+
`${ I._( localIndent ) }for ( let key${ index } in dataSet${ index } ) {` + '\n' +
|
|
322
|
+
`${ I._( localIndent + 1 ) }const dataSetValue${ index } = dataSet${ index }[ key${ index } ]` + '\n'
|
|
323
|
+
|
|
324
|
+
args.push( `dataSetValue${ index }` )
|
|
325
|
+
|
|
326
|
+
forLoopCloses = `${ I._( localIndent ) }}` + '\n' +
|
|
327
|
+
`${ I._( localIndent - 1 ) }}` + '\n' +
|
|
328
|
+
`${ forLoopCloses }`
|
|
329
|
+
|
|
330
|
+
} else {
|
|
331
|
+
|
|
332
|
+
dataSets += `${ I._( indent ) }const dataSet${ index } = _dataMap[ '${ parameterType }s' ]` + '\n'
|
|
333
|
+
// dataSets += `${ I._( indent ) }const dataSet${ index } = this._dataMap[ '${ parameterType }s' ]` + '\n'
|
|
334
|
+
forLoopOpens += '' + '\n' +
|
|
335
|
+
`${ I._( localIndent ) }for ( let key${ index } in dataSet${ index } ) {` + '\n' +
|
|
336
|
+
`${ I._( localIndent + 1 ) }const dataSetValue${ index } = dataSet${ index }[ key${ index } ]` + '\n'
|
|
337
|
+
|
|
338
|
+
args.push( `dataSetValue${ index }` )
|
|
339
|
+
|
|
340
|
+
forLoopCloses = `${ I._( localIndent ) }}` + '\n' + `${ forLoopCloses }`
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
index++
|
|
346
|
+
localIndent++
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const result = `${ I._( localIndent ) }const result = ${ nsName }.${ docData.name }( ${ args.join( ', ' ) } )` + '\n'
|
|
350
|
+
|
|
351
|
+
let expect = ''
|
|
352
|
+
if ( lowerName.startsWith( 'array' ) ) {
|
|
353
|
+
expect = `${ I._( localIndent ) }expect(result).to.be.a('array')` + '\n'
|
|
354
|
+
//todo array of...
|
|
355
|
+
} else {
|
|
356
|
+
expect = `${ I._( localIndent ) }expect(result).to.be.a('${ lowerName }')` + '\n'
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const param = '' +
|
|
360
|
+
`${ dataSets }` +
|
|
361
|
+
`${ forLoopOpens }` +
|
|
362
|
+
`${ result }` +
|
|
363
|
+
`${ expect }` +
|
|
364
|
+
`${ forLoopCloses }`
|
|
365
|
+
|
|
366
|
+
its += '' +
|
|
367
|
+
`${ I._( baseIndent ) }it( 'should return value of type ${ lowerName } when ${ itDeclaration.join( ' and ' ) }', async function() {` + '\n' +
|
|
368
|
+
'\n' +
|
|
369
|
+
`${ param }` +
|
|
370
|
+
'\n' +
|
|
371
|
+
`${ I._( baseIndent ) }} )` + '\n'
|
|
372
|
+
|
|
373
|
+
} else {
|
|
374
|
+
|
|
375
|
+
let itDeclaration = []
|
|
376
|
+
let index = 0
|
|
377
|
+
let indent = baseIndent + 1
|
|
378
|
+
let localIndent = indent
|
|
379
|
+
let dataSets = ''
|
|
380
|
+
let forLoopOpens = ''
|
|
381
|
+
let forLoopCloses = ''
|
|
382
|
+
let args = []
|
|
383
|
+
for ( let parameter of parameters ) {
|
|
384
|
+
|
|
385
|
+
const parameterType = parameter.types[ 0 ]
|
|
386
|
+
itDeclaration.push( `${ parameter.name } is of type ${ parameterType }` )
|
|
387
|
+
|
|
388
|
+
dataSets += `${ I._( localIndent ) }const dataSet${ index } = _dataMap[ '${ parameterType }s' ]` + '\n'
|
|
389
|
+
// dataSets += `${ I._( indent ) }const dataSet${ index } = this._dataMap[ '${ parameterType }s' ]` + '\n'
|
|
390
|
+
forLoopOpens += '' + '\n' +
|
|
391
|
+
`${ I._( localIndent ) }for ( let key${ index } in dataSet${ index } ) {` + '\n' +
|
|
392
|
+
`${ I._( localIndent + 1 ) }const dataSetValue${ index } = dataSet${ index }[ key${ index } ]` + '\n'
|
|
393
|
+
|
|
394
|
+
args.push( `dataSetValue${ index }` )
|
|
395
|
+
|
|
396
|
+
forLoopCloses = `${ I._( localIndent ) }}` + '\n' + `${ forLoopCloses }`
|
|
397
|
+
|
|
398
|
+
index++
|
|
399
|
+
localIndent++
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const result = `${ I._( localIndent + 1 ) }const result = ${ nsName }.${ docData.name }( ${ args.join( ', ' ) } )` + '\n'
|
|
403
|
+
|
|
404
|
+
let returnTypesLabel = []
|
|
405
|
+
let oneOf = []
|
|
406
|
+
for ( let returnType of returns ) {
|
|
407
|
+
|
|
408
|
+
const lowerName = returnType.toLowerCase()
|
|
409
|
+
returnTypesLabel.push( lowerName )
|
|
410
|
+
|
|
411
|
+
if ( lowerName.startsWith( 'array' ) ) {
|
|
412
|
+
//todo array of...
|
|
413
|
+
oneOf.push( 'array' )
|
|
414
|
+
} else {
|
|
415
|
+
oneOf.push( `'${ lowerName }'` )
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const underlyingType = `${ I._( localIndent + 1 ) }const resultType = (result === null) ? 'null' : typeof result` + '\n'
|
|
421
|
+
const expect = `${ I._( localIndent + 1 ) }expect(resultType).to.be.oneOf([${ oneOf.join( ',' ) }])` + '\n'
|
|
422
|
+
|
|
423
|
+
const param = '' +
|
|
424
|
+
`${ dataSets }` +
|
|
425
|
+
`${ forLoopOpens }` +
|
|
426
|
+
`${ result }` +
|
|
427
|
+
`${ underlyingType }` +
|
|
428
|
+
`${ expect }` +
|
|
429
|
+
`${ forLoopCloses }`
|
|
430
|
+
|
|
431
|
+
its += '' +
|
|
432
|
+
`${ I._( baseIndent ) }it( 'should return value of type ${ returnTypesLabel.join( ' or ' ) } when ${ itDeclaration.join( ' and ' ) }', async function() {` + '\n' +
|
|
433
|
+
'\n' +
|
|
434
|
+
`${ param }` +
|
|
435
|
+
'\n' +
|
|
436
|
+
`${ I._( baseIndent ) }} )` + '\n'
|
|
437
|
+
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
describes += '' +
|
|
443
|
+
`${ I_ }describe( '${ docData.name }()', function () {` + '\n' +
|
|
444
|
+
'\n' +
|
|
445
|
+
`${ I__ }it( 'should be bundlable', async function () {` + '\n' +
|
|
446
|
+
'\n' +
|
|
447
|
+
`${ I___ }expect(${ nsName }.${ docData.name }).to.exist` + '\n' +
|
|
448
|
+
'\n' +
|
|
449
|
+
`${ I__ }} )` + '\n' +
|
|
450
|
+
'\n' +
|
|
451
|
+
`${ its }` +
|
|
452
|
+
'\n' +
|
|
453
|
+
`${ I_ }} )` + '\n' +
|
|
454
|
+
'\n'
|
|
455
|
+
|
|
456
|
+
} catch ( error ) {
|
|
457
|
+
|
|
458
|
+
log( red( error.message ) )
|
|
459
|
+
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const template = '' +
|
|
465
|
+
`import { expect } from 'chai'` + '\n' +
|
|
466
|
+
`import { Testing } from 'itee-utils/sources/testings/benchmarks.js'` + '\n' +
|
|
467
|
+
`import * as ${ nsName } from '${ importFilePath }'` + '\n' +
|
|
468
|
+
'\n' +
|
|
469
|
+
`describe( '${ unitName }', function () {` + '\n' +
|
|
470
|
+
'\n' +
|
|
471
|
+
`${ I_ }let _dataMap` + '\n' +
|
|
472
|
+
`${ I_ }before( function() {` + '\n' +
|
|
473
|
+
`${ I__ }_dataMap = Testing.createDataMap()` + '\n' +
|
|
474
|
+
`${ I_ }} )` + '\n' +
|
|
475
|
+
'\n' +
|
|
476
|
+
`${ describes }` +
|
|
477
|
+
'' +
|
|
478
|
+
`} )` + '\n'
|
|
479
|
+
|
|
480
|
+
const importUnitFilePath = relative( unitsDir, unitFilePath )
|
|
481
|
+
unitsImportMap.push( {
|
|
482
|
+
exportName: unitName,
|
|
483
|
+
path: importUnitFilePath.replace( /\\/g, '/' )
|
|
484
|
+
} )
|
|
485
|
+
|
|
486
|
+
createDirectoryIfNotExist( unitDirPath )
|
|
487
|
+
createFile( unitFilePath, template )
|
|
488
|
+
|
|
489
|
+
} catch ( error ) {
|
|
490
|
+
|
|
491
|
+
log( red( error.message ) )
|
|
492
|
+
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// If some tests to import generate global units file
|
|
498
|
+
let unitsTemplate
|
|
499
|
+
if ( isNotEmptyArray( unitsImportMap ) ) {
|
|
500
|
+
|
|
501
|
+
let computedImports = []
|
|
502
|
+
for ( let entry of unitsImportMap ) {
|
|
503
|
+
// computedImports.push(`import { ${ entry.exportName } } from './${ entry.path }'`)
|
|
504
|
+
computedImports.push( `export * from './${ entry.path }'` )
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
unitsTemplate = computedImports.join( '\n' )
|
|
508
|
+
|
|
509
|
+
} else {
|
|
510
|
+
|
|
511
|
+
log( 'Warning ', yellow( 'No tests were generated. Create fallback global root import file.' ) )
|
|
512
|
+
const defaultUnitsDir = join( unitsDir, 'default' )
|
|
513
|
+
const defaultUnitsPath = join( defaultUnitsDir, 'default.unit.mjs' )
|
|
514
|
+
|
|
515
|
+
createDirectoryIfNotExist( defaultUnitsDir )
|
|
516
|
+
createFile( defaultUnitsPath, '// Avoid web test runner crash on empty benches' )
|
|
517
|
+
|
|
518
|
+
const prettyPackageName = getPrettyPackageName( '#' )
|
|
519
|
+
unitsTemplate = `describe( '${ prettyPackageName }', () => {} )` + '\n'
|
|
520
|
+
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const unitsFilePath = join( unitsDir, `${ packageName }.units.mjs` )
|
|
524
|
+
createFile( unitsFilePath, unitsTemplate )
|
|
525
|
+
|
|
526
|
+
done()
|
|
527
|
+
|
|
528
|
+
}
|
|
529
|
+
computeUnitTestsTask.displayName = 'compute-unit-tests'
|
|
530
|
+
computeUnitTestsTask.description = 'Will generate unit test files from source code using type inference from comments'
|
|
531
|
+
computeUnitTestsTask.flags = null
|
|
532
|
+
|
|
533
|
+
logLoadingTask( import.meta.filename, computeUnitTestsTask, configurationPath )
|
|
534
|
+
|
|
535
|
+
export { computeUnitTestsTask }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import colors from 'ansi-colors'
|
|
2
|
+
import { spawn } from 'child_process'
|
|
3
|
+
import log from 'fancy-log'
|
|
4
|
+
import { existsSync } from 'fs'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
import {
|
|
7
|
+
logLoadingTask,
|
|
8
|
+
packageName,
|
|
9
|
+
packageNodeModulesDirectory,
|
|
10
|
+
packageTestsUnitsDirectory
|
|
11
|
+
} from '../../_utils.mjs'
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
red,
|
|
15
|
+
yellow,
|
|
16
|
+
} = colors
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @description Will run unit tests with node
|
|
20
|
+
*/
|
|
21
|
+
const runUnitTestsForBackendTask = ( done ) => {
|
|
22
|
+
|
|
23
|
+
const testsPath = join( packageTestsUnitsDirectory, `/${ packageName }.units.mjs` )
|
|
24
|
+
if ( !existsSync( testsPath ) ) {
|
|
25
|
+
log( yellow( `${ testsPath } does not exist, skip backend unit tests...` ) )
|
|
26
|
+
done()
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const mochaPath = join( packageNodeModulesDirectory, '/mocha/bin/mocha' )
|
|
31
|
+
const mocha = spawn( 'node', [ mochaPath, testsPath ], { stdio: 'inherit' } )
|
|
32
|
+
mocha.on( 'close', ( code ) => {
|
|
33
|
+
|
|
34
|
+
( code === 0 )
|
|
35
|
+
? done()
|
|
36
|
+
: done( red( `mocha exited with code ${ code }` ) )
|
|
37
|
+
|
|
38
|
+
} )
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
runUnitTestsForBackendTask.displayName = 'run-unit-tests-for-backend'
|
|
42
|
+
runUnitTestsForBackendTask.description = 'Will run unit tests with node'
|
|
43
|
+
runUnitTestsForBackendTask.flags = null
|
|
44
|
+
|
|
45
|
+
logLoadingTask( import.meta.filename, runUnitTestsForBackendTask )
|
|
46
|
+
|
|
47
|
+
export { runUnitTestsForBackendTask }
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { startTestRunner } from '@web/test-runner'
|
|
2
|
+
import colors from 'ansi-colors'
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import {
|
|
5
|
+
getConfigurationFrom,
|
|
6
|
+
getConfigurationPathFor,
|
|
7
|
+
logLoadingTask
|
|
8
|
+
} from '../../_utils.mjs'
|
|
9
|
+
|
|
10
|
+
const { red } = colors
|
|
11
|
+
|
|
12
|
+
const configurationLocation = join( 'tests', 'units', 'run-unit-tests-for-frontend.conf.mjs' )
|
|
13
|
+
const configurationPath = getConfigurationPathFor( configurationLocation )
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description Will run unit tests with web-test-runner
|
|
17
|
+
*/
|
|
18
|
+
const runUnitTestsForFrontendTask = () => {
|
|
19
|
+
return new Promise( async ( resolve, reject ) => {
|
|
20
|
+
|
|
21
|
+
const configuration = await getConfigurationFrom( configurationPath )
|
|
22
|
+
const testRunner = await startTestRunner( {
|
|
23
|
+
config: configuration,
|
|
24
|
+
readCliArgs: false,
|
|
25
|
+
readFileConfig: false,
|
|
26
|
+
autoExitProcess: false,
|
|
27
|
+
} )
|
|
28
|
+
|
|
29
|
+
if ( !testRunner ) {
|
|
30
|
+
reject( red( 'Internal test runner error.' ) )
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// To ensure that testRunner exit event won't be used by other instance of test runner,
|
|
35
|
+
// we need to be sure that current test runner is ended
|
|
36
|
+
testRunner.on( 'finished', () => {
|
|
37
|
+
testRunner.stop()
|
|
38
|
+
} )
|
|
39
|
+
|
|
40
|
+
testRunner.on( 'stopped', () => {
|
|
41
|
+
resolve()
|
|
42
|
+
} )
|
|
43
|
+
|
|
44
|
+
} )
|
|
45
|
+
}
|
|
46
|
+
runUnitTestsForFrontendTask.displayName = 'run-unit-tests-for-frontend'
|
|
47
|
+
runUnitTestsForFrontendTask.description = 'Will run unit tests with web-test-runner'
|
|
48
|
+
runUnitTestsForFrontendTask.flags = null
|
|
49
|
+
|
|
50
|
+
logLoadingTask( import.meta.filename, runUnitTestsForFrontendTask, configurationPath )
|
|
51
|
+
|
|
52
|
+
export { runUnitTestsForFrontendTask }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { join } from 'path'
|
|
2
|
+
import {
|
|
3
|
+
getConfigurationFrom,
|
|
4
|
+
getConfigurationPathFor,
|
|
5
|
+
logLoadingTask,
|
|
6
|
+
serializeTasksFrom
|
|
7
|
+
} from '../../_utils.mjs'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const configurationLocation = join( 'tests', 'units', 'run-unit-tests.conf.mjs' )
|
|
11
|
+
const configurationPath = getConfigurationPathFor( configurationLocation )
|
|
12
|
+
const configuration = await getConfigurationFrom( configurationPath )
|
|
13
|
+
|
|
14
|
+
const runUnitTestsTask = await serializeTasksFrom( configuration )
|
|
15
|
+
runUnitTestsTask.displayName = 'run-unit-tests'
|
|
16
|
+
runUnitTestsTask.description = 'Will run unit tests in back and front environments.'
|
|
17
|
+
runUnitTestsTask.flags = null
|
|
18
|
+
|
|
19
|
+
logLoadingTask( import.meta.filename, runUnitTestsTask, configurationPath )
|
|
20
|
+
|
|
21
|
+
export { runUnitTestsTask }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Avoid web test runner crash on empty benches
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Avoid web test runner crash on empty benches
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
describe( 'Itee#Tasks', function() {} )
|