@charmander/test
Advanced tools
Comparing version 0.3.0 to 0.4.0-pre
120
index.js
'use strict'; | ||
const Test = require('./internal/test'); | ||
const TestItem = require('./internal/test-item'); | ||
const run = require('./internal/run'); | ||
const defaultOutput = require('./internal/output'); | ||
let runScheduled = false; | ||
const readonly = value => ({ | ||
configurable: true, | ||
value, | ||
}); | ||
const runMainTests = () => { | ||
const tests = Object.freeze(require.main.exports); | ||
run(defaultOutput, tests); | ||
const root = require.main.exports; | ||
root._freeze(); | ||
run(defaultOutput, root, (error, summary) => { | ||
if (error) { | ||
throw error; | ||
} | ||
defaultOutput.done(summary); | ||
}); | ||
}; | ||
const addTestWithPrefix = (testModule, prefix) => { | ||
const addTest = (name, run) => { | ||
if (typeof name !== 'string') { | ||
throw new TypeError('Test name must be a string'); | ||
const checkPush = (items, item) => { | ||
if (!Object.isExtensible(items)) { | ||
throw new Error('Can’t add test items during test run'); | ||
} | ||
items.push(item); | ||
}; | ||
class TestGroup { | ||
constructor(path) { | ||
this.path = path; | ||
this.tests = []; | ||
this.setup = []; | ||
this.teardown = []; | ||
this.groups = []; | ||
} | ||
addTest(name, run) { | ||
checkPush(this.tests, new TestItem([...this.path, name], run)); | ||
} | ||
addSetup(name, run) { | ||
if (run === undefined) { | ||
run = name; | ||
name = 'setup'; | ||
} | ||
if (!Object.isExtensible(testModule.exports)) { | ||
throw new Error('Can’t add tests during test run'); | ||
checkPush(this.setup, new TestItem([...this.path, name], run)); | ||
} | ||
addTeardown(name, run) { | ||
if (run === undefined) { | ||
run = name; | ||
name = 'teardown'; | ||
} | ||
const prefixedName = [...prefix, name].join(' › '); | ||
checkPush(this.teardown, new TestItem([...this.path, name], run)); | ||
} | ||
testModule.exports.push(new Test(prefixedName, run)); | ||
}; | ||
const addGroup = (name, contents) => { | ||
addGroup(name, contents) { | ||
if (typeof name !== 'string') { | ||
@@ -34,17 +69,48 @@ throw new TypeError('Group name must be a string'); | ||
const addGroupedTest = addTestWithPrefix(testModule, [...prefix, name]); | ||
contents(addGroupedTest); | ||
}; | ||
if (!Object.isExtensible(this.groups)) { | ||
throw new Error('Can’t add groups during test run'); | ||
} | ||
Object.defineProperty(addTest, 'group', { | ||
configurable: true, | ||
value: addGroup, | ||
}); | ||
const group = new TestGroup([...this.path, name]); | ||
this.groups.push(group); | ||
contents(group._boundAddTest()); | ||
} | ||
return addTest; | ||
}; | ||
_freeze() { | ||
Object.freeze(this.tests); | ||
Object.freeze(this.groups); | ||
Object.freeze(this.setup); | ||
Object.freeze(this.teardown); | ||
for (const group of this.groups) { | ||
group._freeze(); | ||
} | ||
} | ||
_boundAddTest() { | ||
const test = (name, run) => { | ||
this.addTest(name, run); | ||
}; | ||
Object.defineProperties(test, { | ||
group: readonly((name, contents) => { | ||
this.addGroup(name, contents); | ||
}), | ||
setup: readonly((name, action) => { | ||
this.addSetup(name, action); | ||
}), | ||
teardown: readonly((name, action) => { | ||
this.addTeardown(name, action); | ||
}), | ||
}); | ||
return test; | ||
} | ||
} | ||
let runScheduled = false; | ||
module.exports = testModule => { | ||
if (!Array.isArray(testModule.exports)) { | ||
testModule.exports = []; | ||
if (!(testModule.exports instanceof TestGroup)) { | ||
testModule.exports = new TestGroup([]); | ||
} | ||
@@ -57,3 +123,3 @@ | ||
return addTestWithPrefix(testModule, []); | ||
return testModule.exports._boundAddTest(); | ||
}; |
'use strict'; | ||
module.exports = { | ||
enter(test) { | ||
console.log(test.name); | ||
enter: e => { | ||
console.log(e.item.path.join(' > ')); | ||
}, | ||
leave(e) { | ||
if (!e.pass) { | ||
leave: e => { | ||
if (e.type === 'test' && !e.pass) { | ||
const {error} = e; | ||
@@ -18,3 +18,3 @@ | ||
}, | ||
done(result) { | ||
done: result => { | ||
const {pass, total} = result; | ||
@@ -21,0 +21,0 @@ |
@@ -11,6 +11,8 @@ 'use strict'; | ||
const terminate = (promise, success) => { | ||
const terminate = (promise, success, failure) => { | ||
promise.then( | ||
callNextTick(success), | ||
throwNextTick | ||
failure === undefined ? | ||
throwNextTick : | ||
callNextTick(failure) | ||
); | ||
@@ -17,0 +19,0 @@ }; |
@@ -5,33 +5,101 @@ 'use strict'; | ||
const run = (output, tests) => { | ||
let pass = 0; | ||
const forEach = (array, action, callback) => { | ||
let i = 0; | ||
const length = array.length; | ||
const next = () => { | ||
if (i === tests.length) { | ||
output.done({pass, total: tests.length}); | ||
const next = error => { | ||
if (error || i === length) { | ||
callback(error); | ||
return; | ||
} | ||
const test = tests[i]; | ||
action(array[i++], next); | ||
}; | ||
output.enter(test); | ||
next(null); | ||
}; | ||
const runTests = (output, tests, callback) => { | ||
let pass = 0; | ||
forEach( | ||
tests, | ||
(test, callback) => { | ||
const e = {item: test, type: 'test'}; | ||
output.enter(e); | ||
terminate( | ||
test.run().then( | ||
() => ({item: test, type: 'test', pass: true, error: null}), | ||
error => ({item: test, type: 'test', pass: false, error}) | ||
), | ||
result => { | ||
pass += result.pass; | ||
output.leave(result); | ||
callback(null); | ||
} | ||
); | ||
}, | ||
error => { | ||
callback(error, {pass, total: tests.length}); | ||
} | ||
); | ||
}; | ||
const runEssential = (type, output, items, callback) => { | ||
forEach(items, (item, callback) => { | ||
const e = {item, type}; | ||
output.enter(e); | ||
terminate( | ||
test.run().then( | ||
() => ({test, pass: true, error: null}), | ||
error => ({test, pass: false, error}) | ||
), | ||
result => { | ||
pass += result.pass; | ||
output.leave(result); | ||
i++; | ||
next(); | ||
} | ||
item.run(), | ||
() => { | ||
output.leave(e); | ||
callback(null); | ||
}, | ||
callback | ||
); | ||
}; | ||
}, callback); | ||
}; | ||
next(); | ||
const run = (output, group, callback) => { | ||
runEssential('setup', output, group.setup, error => { | ||
if (error) { | ||
callback(error, undefined); | ||
return; | ||
} | ||
runTests(output, group.tests, (error, summary) => { | ||
if (error) { | ||
callback(error, undefined); | ||
return; | ||
} | ||
forEach( | ||
group.groups, | ||
(group, callback) => { | ||
run(output, group, callback); | ||
}, | ||
error => { | ||
if (error) { | ||
callback(error, undefined); | ||
return; | ||
} | ||
runEssential('teardown', output, group.teardown, error => { | ||
if (error) { | ||
callback(error, undefined); | ||
return; | ||
} | ||
callback(null, summary); | ||
}); | ||
} | ||
); | ||
}); | ||
}); | ||
}; | ||
module.exports = run; |
{ | ||
"name": "@charmander/test", | ||
"version": "0.3.0", | ||
"version": "0.4.0-pre", | ||
"description": "Basic test organization", | ||
@@ -19,3 +19,3 @@ "keywords": [ | ||
"internal/promise-terminate.js", | ||
"internal/test.js", | ||
"internal/test-item.js", | ||
"internal/run.js", | ||
@@ -22,0 +22,0 @@ "internal/output.js" |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
8061
253
1