siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
282 lines (207 loc) • 9 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
!function () {
var fs = require('fs')
var path = require('path')
Class('Siesta.Launcher.DiscoverTool', {
does : [
Siesta.Launcher.CommandLineTool.BaseTool,
Siesta.Launcher.CommandLineTool.NodeJSTool,
Siesta.Util.Role.CanGetType,
Siesta.Util.Role.CanEscapeRegExp
],
has : {
helpIntro : function () {
return [
'Usage: discover [OPTIONS] desc_file.json dir1 dir2 ... dirN',
'All options are optional.',
'',
'This tool will scan the provided dirs and create a corresponding',
'set of test descriptors in the `desc_file.json`. This file is',
'suitable for usage with the project `startFromUrl` method.',
'Existing content of `desc_file.json` will be preservered',
'as much as possible',
''
]
},
knownOptionGroups : {
init : {
'00-system' : {
name : 'Base options'
}
}
},
knownOptions : {
init : [
{
name : 'help',
desc : 'Prints this help message and exit',
group : '00-system'
},
{
name : 'version',
desc : 'Prints versions of Siesta and automation component and exit',
group : '00-system'
},
{
name : 'overwrite',
desc : 'Overwrite any existing content of the `desc.json` file, w/o trying to preserve it',
group : '00-system'
},
{
name : 'ext',
desc : 'Test file extension, default value is "t.js"',
group : '00-system'
},
{
name : 'base-dir',
desc : [
'Test base directory (directory with your project html file), all other file paths',
'will be resolved relative to that dir.'
],
group : '00-system'
}
]
},
descriptorsFile : null,
descriptors : null
},
override : {
prepareOptions : function (callback) {
var me = this
this.SUPER(function (e) {
if (e) { callback(e); return }
if (me.argv.length < 2) {
me.printError("Should have at least 2 positional arguments - first one is the JSON file with test descriptors, second - directory to scan for test files.")
me.printHelp()
callback(true)
return
}
me.descriptorsFile = me.argv.shift()
var fileName = me.descriptorsFile
if (me.fileExists(fileName) && !me.options.overwrite) {
var json
try {
json = me.readFile(fileName)
} catch (e) {
me.printError([
me.formatString("Can't read the content of the JSON file: {fileName}", { fileName : fileName })
])
callback(true)
return
}
try {
json = JSON.parse(json)
if (me.typeOf(json) != 'Array') throw "not an array"
me.descriptors = json
} catch (e) {
if (!me.options.overwrite) {
me.printError([
me.formatString("JSON file does not contain valid JSON array: {fileName}", { fileName : fileName })
])
callback(true)
return
}
}
}
callback()
})
}
},
methods : {
start : function (callback) {
var me = this
this.prepareOptions(function (e) {
if (e) { callback(null, 1); return }
me.launch(callback)
})
},
createIndex : function (descriptors, parentDesc, index) {
var me = this
index = index || { groups : {}, tests : {} }
Joose.A.each(descriptors, function (desc) {
if (desc)
if (desc.group) {
desc.id = parentDesc ? parentDesc.id + '/' + desc.group : desc.group
var hasSpecialConfig = false
for (var i in desc)
if (i != 'group' && i != 'items' && i != 'id') { hasSpecialConfig = true; break; }
if (hasSpecialConfig) index.groups[ desc.id ] = desc
me.createIndex(desc.items, desc, index)
} else
if (typeof desc != 'string' && desc.url) index.tests[ desc.url ] = desc
})
return index
},
launch : function (callback) {
var me = this
var groups = []
var index
if (me.descriptors) index = this.createIndex(me.descriptors)
Joose.A.each(this.argv, function (dir) {
groups.push(me.scanDir(dir, index))
})
this.saveFile(this.descriptorsFile, require('js-beautify').js_beautify(JSON.stringify(groups), {
// wrap the line at the first chance
wrap_line_length : 1,
brace_style : "expand"
}))
callback()
},
scanDir : function (dir, index, recurseCall) {
dir = path.resolve(this.normalizePath(dir))
var me = this
var items = []
var group = { group : path.basename(dir) + '' }
var baseDir = path.resolve(this.options[ 'base-dir' ] || '')
var regexp = new RegExp(this.escapeRegExp((this.options.ext || '.t.js')) + '$')
Joose.A.each(fs.readdirSync(dir), function (file) {
file = path.resolve(dir, file)
var stat = fs.statSync(file)
if (stat.isDirectory()) {
var id = path.basename(dir) + '/' + path.relative(dir, file)
var subGroup = me.scanDir(file, index, true)
if (index && index.groups[ id ]) {
me.mergePropsFromExistingDesc(subGroup, index.groups[ id ], true)
// re-assign to "items" property go last
var prev = subGroup.items
delete subGroup.items
subGroup.items = prev
}
if (subGroup.items.length || index && index.groups[ id ]) items.push(subGroup)
} else
if (regexp.test(file)) {
var relativePath = path.relative(baseDir, file).replace(/\\/g, '/')
if (index && index.tests[ relativePath ])
items.push(me.mergePropsFromExistingDesc({ url : relativePath }, index.tests[ relativePath ], false))
else
items.push(relativePath)
}
})
if (!recurseCall) {
var topDirId = path.basename(dir)
if (index && index.groups[ topDirId ]) me.mergePropsFromExistingDesc(group, index.groups[ topDirId ], true)
}
// asign last so that in stringified form it goes also last
group.items = items
return group
},
mergePropsFromExistingDesc : function (newDesc, oldDesc, isGroup) {
for (var i in oldDesc) {
if (isGroup && i != 'group' && i != 'items' && i != 'id' || !isGroup && i != 'url')
newDesc[ i ] = oldDesc [ i ]
}
return newDesc
},
printVersion : function () {
var siestaAll = this.readFile(this.binDir + '../siesta-all.js')
var match = /^\/\*[\s\S]*?Siesta (\d.+)\n/.exec(siestaAll)
if (match) this.print("Siesta : " + match[ 1 ])
}
}
})
}()