jupyter-js-auto-test
Version:
Auto scan files under the directory and run test in them
233 lines (208 loc) • 8.74 kB
JavaScript
/**
* This project could scan files under the specific directory and run tests in them. The test
* report could be print to the terminal or pass to the caller via Callback.
*
* It Requires package of parse-commandline-arguments
*
* How to write test:
* 1. write test in other files and export all tests
* 2. this file will scan this directory to find all tests and test them and
* 3. print out test report if these are all reports, if not, callback the test results
*
* How to run test
* There are two ways to run test:
* 1. Run all test: node ./ --local
* 2. Run all test in one specific file: node ./ --only filename --local
* 3. Run specific test in one specific file: node ./ --only filename:functions[,function2,function3,...] --local
* or it could be call as a node module.
* const { setAndRun } = require('jupyter-js-auto-test')
* setAndRun(path[, filename, [function1, function2,...]])
*
* To exclude files, add the filename in the excludeFiles.
* Do not delete 'index.js' as it should always be excluded.
* or requrie('jupyter-js-auto-test).setExcludeFiles(file1, file2, file3,...)
*
* todo:
* 1. in the final test report, failed messages should be formate in a proper way
* Done 2. accept --path to find test in other directory
* 3. output test report to a file as an option
* Done 4. make it as a node module and a node runnable file, should be able to be called by commandline and node require()
* 5. pre-testFuncs could accept functions other than test config
*/
const chalk = require('chalk')
const Promise = require('bluebird')
const { splitFilename, consolePrintTestResultsReportAndCallbackIfNeeded, TestResults } = require('./helpers')
const excludeFiles = ['index.js', 'config.js', 'helpers.js']
let testResultsCallback = null
let isOnlyMode = false
let only = {
filename: '',
functions: []
}
let path = ''
let acceptedArguments = {
only: '',
path: '',
local: '',
}
module.exports = {
registerTestResultsCallback,
setAndRun,
setExcludeFiles,
TestFunctionConfig: require('./helpers').TestFunctionConfig,
readConfigAndRun: require('./helpers').readConfigAndRun,
}
// --only filename:function1,function2
const cmdargs = require('jupyter-parse-commandline-arguments').parseCommandlineArguments(process.argv, acceptedArguments)
if (cmdargs.local) {
runLocal()
}
function setExcludeFiles(...filenames) {
excludeFiles = filenames
}
function setAndRun(path_v, filename, functions) {
path = path_v.endsWith('/') ? path_v : path_v + '/'
if (filename) {
isOnlyMode = true
only.filename = filename
only.functions = functions || []
}
if (cmdargs && cmdargs.local) {
} else {
startTest()
}
}
function runLocal() {
if (cmdargs.only && cmdargs.only !== true) {
params = cmdargs.only.split(':')
isOnlyMode = true
only.filename = params[0]
only.functions = params[1] ? params[1].split(',') : []
console.log(chalk.bgYellow.black("Only mode is on"))
console.log("Only test file", chalk.bgCyan(only.filename), "for ", only.functions.length === 0 ? "all test functions" : "functions:" + JSON.stringify(only.functions))
}
if ((cmdargs.path && cmdargs.path === true) || !cmdargs.path) {
path = './'
} else {
path = cmdargs.path
}
startTest()
}
function startTest() {
console.log("Starting scanning test files in ", path)
require('fs').readdir(path, (error, items) => {
if (!error) {
let tests = {}
let testResults = new TestResults()
items.forEach(item => {
if (excludeFiles.indexOf(item) < 0) {
const { filename, extension } = splitFilename(item)
if (extension === 'js') {
if ((isOnlyMode && (only.filename === filename || only.filename === filename + '.js'))
|| !isOnlyMode) {
tests[filename] = require(path + filename)
testResults.totalTest += Object.keys(tests[filename]).length
}
}
}
})
if (!isOnlyMode) {
console.log(chalk.cyan("Totally have " + testResults.totalTest + ' tests'))
} else {
console.log(chalk.cyan("Totally have no more than " + only.functions.length + ' tests'))
}
testResults.totalTest = 0 // totalTest should be count as the test running
console.log("Start testing...")
let promises = []
Object.keys(tests).forEach(key => {
promises.push(new Promise((resolve, reject) => {
performTest(key, tests[key], (passed, failed, failedMessages) => {
if (isOnlyMode) {
// remove tested functions from the only.functions to know which one in only.functions does not test
passed.forEach(aPassed => {
only.functions.splice(only.functions.indexOf(aPassed), 1)
})
failed.forEach(aFailed => {
only.functions.splice(only.functions.indexOf(aFailed), 1)
})
}
testResults.passed[key] = passed
testResults.failed[key] = failed
testResults.passedCount += passed.length
testResults.failedCount += failed.length
testResults.totalTest += passed.length + failed.length
testResults.failedMessages[key] = failedMessages
resolve()
})
}))
})
Promise.all(promises).then(() => {
if (only.functions.length > 0) {
console.log(chalk.yellow('Cannot find these functions '), only.functions)
}
consolePrintTestResultsReportAndCallbackIfNeeded(testResults, testResultsCallback)
})
} else {
console.log(chalk.red(JSON.stringify(error)))
}
})
}
function setPath(path) {
cmdargs.path = path
return this
}
function performTest(testname, tests, callback) {
const keys = Object.keys(tests)
if (!isOnlyMode) {
console.log("Start to test", testname , chalk.bgCyan(" having " + keys.length + " tests"))
} else {
console.log("Start to test", testname , chalk.bgCyan(" having no more than " + only.functions.length + " tests"))
}
let testResults = {}
let promises = []
keys.forEach(key => {
if ((isOnlyMode && ((only.functions.length > 0 && only.functions.indexOf(key) >=0) || (only.functions.length <= 0)))
|| (!isOnlyMode)) {
promises.push(new Promise((resolve, rejct) => {
tests[key]((res, failedMessage) => {
testResults[key] = {res, failedMessage}
resolve()
})
}))
}
})
Promise.all(promises).then(() => {
let passed = []
let failed = []
let failedMessages = {}
Object.keys(testResults).forEach((key) => {
if (testResults[key].res) {
passed.push(key)
} else {
failed.push(key)
if (testResults[key].failedMessage) {
failedMessages[key] = testResults[key].failedMessage
}
}
})
if (passed.length > 0) {
console.log(chalk.green(testname + " passed:"))
console.log(passed)
}
if (failed.length > 0) {
console.log(chalk.red(testname + " failed:"))
console.log(failed)
}
if (passed.length > 0) {
console.log(chalk.green(testname + " subtotal " + passed.length + " passed"))
}
if (failed.length > 0) {
console.log(chalk.red(testname + " subtotal " + failed.length + " failed"))
}
callback ? callback(passed, failed, failedMessages) : ''
})
}
function registerTestResultsCallback(callback) {
testResultsCallback = callback
return this
}