Prepare first release

This commit is contained in:
Jonatan Nilsson 2020-03-31 17:27:36 +00:00
parent cc34409439
commit 653e54c846
15 changed files with 1215 additions and 2 deletions

64
cli.mjs Normal file
View file

@ -0,0 +1,64 @@
#!/usr/bin/env node
// Get arguments
const [,, ...args] = process.argv
import c from './lib/casette.mjs'
import { CLI, printError } from './lib/cli.mjs'
c.begin()
const cli = new CLI(c)
cli.parseOptions(args)
if (cli.errored) {
PrintHelp()
}
function PrintHelp() {
console.log('')
console.log('Usage: casette <options> <files>')
console.log('')
console.log('where <files> can either be a single file or a simple glob pattern.')
console.log('where <options> can be any of the following:')
console.log(' -r, --reporter - Specify the reporter to use.')
console.log(' Supported reporters: list, dot')
console.log('')
console.log('casette test/mytest.mjs')
console.log('casette dot test/*.mjs')
console.log('casette -r dot test/**/*.test.mjs')
process.exit(1)
}
cli.processTargets().then(function() {
if (!cli.files.length) {
console.log('')
console.log('No files were found with pattern', cli.targets.join(','))
PrintHelp()
}
return cli.loadFiles()
.then(function() {
c.reporter = cli.reporter
return c.run()
.catch(function(err) {
console.log('')
console.error('\x1b[31mUnknown error occured while running the tests\x1b[0m')
printError(err)
process.exit(1)
})
}, function(err) {
console.log('')
console.error('\x1b[31mUnknown error while opening files\x1b[0m')
printError(err)
process.exit(1)
})
}, function(err) {
console.log('')
console.error('\x1b[31mUnknown error while processing arguments\x1b[0m')
printError(err)
process.exit(1)
})
.then(function() {
process.exit(0)
})

7
index.mjs Normal file
View file

@ -0,0 +1,7 @@
import Casette from './lib/casette.mjs'
import assert from './lib/assert.mjs'
export {
Casette,
assert,
}

83
lib/assert.mjs Normal file
View file

@ -0,0 +1,83 @@
import assert from 'assert'
import util from 'util'
const fail = assert.fail;
function truncate(s, n) {
return s.length < n ? s : s.slice(0, n) + '...';
}
function stringifyObject(data) {
if (typeof(data) !== 'string') {
data = util.inspect(
data,
{ depth: 1 }
)
.replace(/\n /g, '');
}
return truncate(data, 64);
}
assert.notOk = (value, message) => {
if (Boolean(value)) {
assert.equal(value, false, message)
}
}
assert.match = (value, test, message) => {
let result = value.match(test);
if (result) return;
let m = message
if (!m) {
m = `${value} did not match ${test}`
}
fail(m);
}
assert.notMatch = (value, test, message) => {
let result = value.match(test);
if (!result) return;
let m = message
if (!m) {
m = `${value} matched ${test}`
}
fail(m);
}
assert.isFulfilled = (promise, message) => {
return Promise.resolve(true)
.then(() => promise)
.catch((err) => {
let m = message
if (!m) {
m = `promise failed with ${err.message || stringifyObject(err)}`;
}
fail(m);
});
}
assert.isRejected = (promise, message) => {
let hasFailed = false;
return Promise.resolve(true)
.then(() => promise)
.catch((data) => {
hasFailed = true;
return data;
})
.then((data) => {
if (hasFailed) return data;
let m = message
if (!m) {
m = `promise was fulfilled with ${stringifyObject(data)}`;
}
fail(m);
});
}
export default assert

263
lib/casette.mjs Normal file
View file

@ -0,0 +1,263 @@
import { printError } from './cli.mjs'
function Group(name) {
this.name = name
this.tests = []
}
function Test(name, func) {
this.skipTest = false
this.customTimeout = null
this.name = name
this.func = func
this.group = null
this.error = null
}
Test.prototype.timeout = function(time) {
this.customTimeout = time
}
Test.prototype.skip = function() {
this.skipTest = true
}
function Casette() {
this.__timeout = 2000
this.reporter = 'list'
this.Casette = Casette
this.groups = new Map()
this.groupsFlat = []
this.tests = []
this.failedTests = []
this.hasTests = false
this.starting = false
this.filename = ''
this.prefix = ''
}
Casette.prototype.begin = function() {
if (this.starting) {
console.warn('WARNING: Multiple calls to Casette.begin were done.')
return
}
this.hasTests = false
this.starting = true
this.filename = ''
this.prefix = ''
this.groups.clear()
this.tests.splice(0, this.tests.length)
}
Casette.prototype.__runTest = async function(stats, test) {
if (this.reporter === 'list') {
process.stdout.write(' \x1b[90m? ' + test.name + '\x1b[0m')
}
if (!test.skipTest) {
await new Promise((resolve, reject) => {
// Flag to check if we finished
let finished = false
let timeout = test.customTimeout || this.__timeout
// Timeout timer in case test times out
let timer = setTimeout(function() {
if (finished === true) return
reject(new Error('timeout of ' + timeout + 'ms exceeded. Ensure the done() callback is being called in this test.'))
}, timeout)
// start the test runner
try {
// Does it accept a callback
let checkIsCallback = (test.func.toString()).match(/^(function)? *\([^\)]+\)/)
let promise
// If the test requires callback, wrap it in a promise where callback
// either resolves or rejects that promise
if (checkIsCallback) {
promise = new Promise(function(res, rej) {
test.func(function(err) {
if (err) {
return rej(err)
}
res()
})
})
} else {
// Function doesn't require a callback, run it directly
promise = test.func()
}
// Check if the function we ran returned a promise
if (promise && promise.then && typeof(promise.then === 'function')) {
// If the promise from the function succeeded, resolve our promise.
// Otherwise reject it
promise.then(function() {
// check if our test had already finished and if so, do nothing
if (finished === true) return
finished = true
clearTimeout(timer)
resolve()
}, function(err) {
// check if our test had already finished and if so, do nothing
if (finished === true) return
finished = true
clearTimeout(timer)
reject(err)
})
} else {
// check if our test had already finished and if so, do nothing
if (finished === true) return
// Possible this was a synchronous test, pass immediately
finished = true
clearTimeout(timer)
resolve()
}
} catch (err) {
// check if our test had already finished and if so, do nothing
if (finished === true) return
// An error occured while running function. Possible exception
// during a synchronous test or something else.
finished = true
clearTimeout(timer)
reject(err)
}
})
.then(function() {
stats.passed++
}, function(err) {
test.error = err
stats.failed++
}
)
} else {
stats.skipped++
}
if (test.error) {
this.failedTests.push(test)
}
if (this.reporter === 'list') {
process.stdout.clearLine();
process.stdout.cursorTo(0);
if (test.skipTest) {
process.stdout.write(' \x1b[94m- ' + test.name + '\x1b[0m\n')
} else if (!test.error) {
process.stdout.write(' \x1b[32m√\x1b[90m ' + test.name + '\x1b[0m\n')
} else {
process.stdout.write(' \x1b[31m' + this.failedTests.length + ') ' + test.name + '\x1b[0m\n')
}
} else if (this.reporter === 'dot') {
if (test.skipTest) {
process.stdout.write('\x1b[94m.\x1b[0m')
} else if (!test.error) {
process.stdout.write('\x1b[32m.\x1b[0m')
} else {
process.stdout.write('\x1b[31m.\x1b[0m')
}
}
}
Casette.prototype.run = async function() {
if (this.reporter) {
console.log('')
console.log('')
}
let stats = {
passed: 0,
failed: 0,
skipped: 0,
}
let start = process.hrtime()
for (let i = 0; i < this.groupsFlat.length; i++) {
let g = this.groupsFlat[i];
if (this.reporter === 'list') {
console.log(' ' + g.name)
}
for (let x = 0; x < g.tests.length; x++) {
await this.__runTest(stats, g.tests[x])
}
}
for (let x = 0; x < this.tests.length; x++) {
await this.__runTest(stats, this.tests[x])
}
let end = process.hrtime(start)
if (this.reporter) {
console.log('')
console.log('')
if (stats.passed) {
console.log(' \x1b[32m' + stats.passed + ' passing \x1b[90m(' + (end[0] * 1000 + Math.round(end[1] / 1000000)) + 'ms)\x1b[0m')
}
if (stats.failed) {
console.log(' \x1b[31m' + stats.failed + ' failing\x1b[0m')
}
if (stats.skipped) {
console.log(' \x1b[94m' + stats.skipped + ' pending\x1b[0m')
}
console.log('')
if (this.failedTests.length) {
for (let x = 0; x < this.failedTests.length; x++) {
let test = this.failedTests[x];
console.log(' ' + (x + 1) + ') '
+ (test.group ? test.group.name + ': ' : '' )
+ test.name + ':'
)
printError(test.error)
}
}
}
}
Casette.prototype.setFilename = function(filename) {
this.filename = filename
}
Casette.prototype.resetFilename = function() {
this.filename = ''
}
Casette.prototype.describe = function(name, func) {
let before = this.prefix
if (before) {
this.prefix = before + ' ' + name
} else {
this.prefix = name
}
func()
this.prefix = before
}
Casette.prototype.test = function(name, func) {
let targetName = name
if (this.prefix) {
targetName = this.prefix + ' ' + name
}
this.hasTests = true
let group = this
if (this.filename) {
if (!this.groups.has(this.filename)) {
let g = new Group(this.filename)
this.groupsFlat.push(g)
this.groups.set(this.filename, g)
}
group = this.groups.get(this.filename)
}
let test = new Test(targetName, func)
test.group = group
group.tests.push(test)
return test
}
export default new Casette()

169
lib/cli.mjs Normal file
View file

@ -0,0 +1,169 @@
import path from 'path'
import fs from 'fs'
export function CLI(c) {
this.c = c
this.reporter = 'list'
this.targets = ['test/**']
this.files = []
this.errored = false
}
CLI.prototype.parseOptions = function(args) {
if (!args || !args.length) {
this.targets.push('test/**')
this.errored = false
return
}
this.errored = false
this.targets.splice(0, this.targets.length)
for (let i = 0; i < args.length; i++) {
if (args[i] === '-r' || args[i] === '--reporter') {
if (!args[i + 1] || (args[i + 1] !== 'list' && args[i + 1] !== 'dot')) {
this.errored = true
return
}
this.reporter = args[i + 1]
i++
} else {
this.targets.push(args[i])
}
}
if (!this.targets.length) {
this.targets.push('test/**')
}
}
CLI.prototype.processTargets = function() {
this.files.splice(0, this.files.length)
if (!this.targets.length) {
return Promise.resolve()
}
return Promise.all(this.targets.map((target) => {
return getFiles(this.files, target)
})).then(() => {
if (!this.files.length) {
this.errored = 'empty'
}
})
}
CLI.prototype.loadFiles = async function() {
let cwd = process.cwd()
for (let i = 0; i < this.files.length; i++) {
if (this.files[i].endsWith('.mjs') || this.files[i].endsWith('.js')) {
this.c.setFilename(this.files[i])
await import('file:///' + path.join(cwd, this.files[i]))
this.c.resetFilename()
}
}
}
function traverseFolder(files, curr, match, insidePath, grabAll, insideStar, includeFiles) {
return new Promise(function(resolve, reject) {
return fs.readdir(curr, function(err, data) {
if (err) return reject(new Error('unable to read directory ' + curr + ': ' + err.message))
resolve(Promise.all(data.map(function(file) {
return new Promise(function(res, rej) {
fs.lstat(path.join(curr, file), function(err, stat) {
if (err) return rej(new Error('unable to read file or directory ' + path.join(curr, file) + ': ' + err.message))
if ((includeFiles || grabAll) && stat.isFile()) {
if (!match || fileMatches(file, match)) {
files.push(path.join(insidePath, file).replace(/\\/g, '/'))
return res(files)
}
}
if (stat.isDirectory() && grabAll) {
return res(traverseFolder(files, path.join(curr, file), match, path.join(insidePath, file), grabAll, insideStar, includeFiles))
} else if (stat.isDirectory() && match) {
return res(getFiles(files, match, path.join(insidePath, file), grabAll, insideStar))
}
res(null)
})
})
})).then(function() { return files }))
})
})
}
export function fileMatches(filename, match) {
return Boolean(filename.match(new RegExp(match.replace(/\./, '\\.').replace(/\*/, '.*'))))
}
export function getFiles(files, match, insidePath, grabAll, insideStar) {
let isGrabbingAll = grabAll || false
let isStarred = insideStar || false
let cwd = process.cwd()
let currPath = insidePath || ''
let curr = path.join(cwd, currPath || '')
return new Promise(function(res, rej) {
let start = 0
let splitted = match.split('/')
if (splitted[start] === '.') {
start++
}
if (splitted[splitted.length - 1] === '') {
splitted[splitted.length - 1] === '*'
}
let first = splitted[start]
if (splitted.length > start + 1) {
if (first === '**') {
isGrabbingAll = isStarred = true
return traverseFolder(files, curr, splitted.slice(start + 1).join('/'), currPath, isGrabbingAll, isStarred, false)
.then(res, rej)
} else if (first === '*') {
isStarred = true
return traverseFolder(files, curr, splitted.slice(start + 1).join('/'), currPath, isGrabbingAll, isStarred, false)
.then(res, rej)
}
return getFiles(files, splitted.slice(start + 1).join('/'), path.join(currPath, first), grabAll, isStarred)
.then(res, rej)
} else if (first.indexOf('*') >= 0) {
if (first === '**') {
isGrabbingAll = isStarred = true
}
return traverseFolder(files, curr, first === '*' || first === '**'? '' : first, currPath, isGrabbingAll, isStarred, true)
.then(res, rej)
}
fs.lstat(path.join(curr, first), function(err, stat) {
if (err) {
// If we're inside a star, we ignore files we cannot find
if (isStarred) {
return res(files)
}
return rej(new Error('file ' + path.join(insidePath, first) + ' could not be found: ' + err.message))
}
if (stat.isDirectory()) {
return traverseFolder(files, path.join(curr, first), '', path.join(currPath, first), true, true, true)
.then(res, rej)
}
files.push(path.join(currPath, match).replace(/\\/g, '/'))
return res(files)
})
})
}
export function printError(err, msg) {
let before = msg || ''
console.error('')
console.error('\x1b[31m '
+ before + err.toString()
+ '\x1b[0m\n \x1b[90m'
+ err.stack.replace(err.toString(), ''))
console.error('\x1b[0m')
}

View file

@ -2,7 +2,7 @@
"name": "casette", "name": "casette",
"version": "0.9.0", "version": "0.9.0",
"description": "No-dependancy test framework for node", "description": "No-dependancy test framework for node",
"main": "index.js", "main": "index.mjs",
"scripts": { "scripts": {
"test": "node cli.mjs test/**/*.test.mjs" "test": "node cli.mjs test/**/*.test.mjs"
}, },
@ -25,5 +25,11 @@
"homepage": "https://github.com/TheThing/node-casette#readme", "homepage": "https://github.com/TheThing/node-casette#readme",
"bin": { "bin": {
"casette": "./cli.mjs" "casette": "./cli.mjs"
} },
"files": [
"index.mjs",
"cli.mjs",
"README.md",
"lib"
]
} }

154
test/assert.test.mjs Normal file
View file

@ -0,0 +1,154 @@
import util from 'util'
import assert from 'assert'
import assertExtended from '../lib/assert.mjs'
import c from '../lib/casette.mjs'
const testLongObject = {
a: 1, b:2, c:3, d:4,
e: {herp: 51, derp: 23},
f: 'asdfgagwegawegawegawegawe',
g: '32ghaiwugb23 238023'
}
c.describe('#notOk()', function() {
c.test('should exist', function() {
assertExtended.ok(assertExtended.notOk)
})
c.test('should throw for true values', function() {
assertExtended.throws(function() {
assertExtended.notOk(true)
}, assertExtended.AssertionError)
})
c.test('should pass for false values', function() {
assertExtended.notOk(false)
assertExtended.notOk(null)
assertExtended.notOk(0)
})
})
c.describe('#isFulfilled()', function() {
c.test('should exist', function() {
assertExtended.ok(assertExtended.isFulfilled)
})
c.test('should throw for rejected promises', function() {
return assertExtended.isFulfilled(Promise.reject({}))
.catch((err) => {
assertExtended.ok(err.message.match(/promise fail/))
})
})
c.test('should properly parse rejected object response', function() {
let assertMessage = util.inspect(testLongObject, {depth: 1}).replace(/\n /g, '')
assertMessage = assertMessage.slice(0, 64) + '...'
return assertExtended.isFulfilled(Promise.reject(testLongObject))
.catch((err) =>
assertExtended.notStrictEqual(err.message.indexOf(assertMessage), -1)
)
})
c.test('should include error message if error', function() {
const assertMessage = 'something something dark side'
return assertExtended.isFulfilled(Promise.reject(new Error(assertMessage)))
.catch((err) => {
assertExtended.ok(err.message.match(new RegExp('with ' + assertMessage)))
})
})
c.test('should pass for resolved promises', function() {
return assertExtended.isFulfilled(Promise.resolve())
})
c.test('should support custom message', function() {
const assertMessage = 'something something dark side'
return assertExtended.isFulfilled(Promise.reject({}), assertMessage)
.catch((err) => {
assertExtended.ok(err.message.match(assertMessage))
})
})
c.test('should return result for the resolved promise', function() {
const assertResult = {a: 1}
return assertExtended.isFulfilled(Promise.resolve(assertResult))
.then((data) => assertExtended.strictEqual(data, assertResult))
})
})
c.describe('#isRejected()', function() {
c.test('should exist', function() {
assertExtended.ok(assertExtended.isRejected)
})
c.test('should throw for resolved promises', function() {
let hasFailed = false
return assertExtended.isRejected(Promise.resolve({}))
.catch((err) => {
hasFailed = true
assertExtended.ok(err.message.match(/fulfilled with/))
})
.then(function() {
assertExtended.strictEqual(hasFailed, true)
})
})
c.test('should properly stringify objects', function() {
let assertMessage = util.inspect(testLongObject, {depth: 1}).replace(/\n /g, '')
assertMessage = assertMessage.slice(0, 64) + '...'
return assertExtended.isRejected(Promise.resolve(testLongObject))
.catch((err) =>
assertExtended.notStrictEqual(err.message.indexOf(assertMessage), -1)
)
})
c.test('should support custom message', function() {
const assertMessage = 'something something dark side'
return assertExtended.isRejected(Promise.resolve({}), assertMessage)
.catch((err) => assertExtended.ok(err.message.match(assertMessage)))
})
c.test('should return result for the unresolved promise', function() {
const assertResult = {a: 1}
return assertExtended.isRejected(Promise.reject(assertResult))
.then((data) => assertExtended.strictEqual(data, assertResult))
})
})
c.describe('#match()', function() {
c.test('should exist', function() {
assertExtended.ok(assertExtended.match);
});
c.test('should throw if no match', function() {
assertExtended.throws(function() {
assertExtended.match('a', /b/);
}, assertExtended.AssertionError);
});
c.test('should pass if matches', function() {
assertExtended.match('a', /a/);
});
})
c.describe('#notMatch()', function() {
c.test('should exist', function() {
assertExtended.ok(assertExtended.notMatch);
});
c.test('should throw if match', function() {
assertExtended.throws(function() {
assertExtended.notMatch('a', /a/);
}, assertExtended.AssertionError);
});
c.test('should pass if not matches', function() {
assertExtended.notMatch('a', /b/);
});
})

192
test/casette.test.mjs Normal file
View file

@ -0,0 +1,192 @@
import c from '../lib/casette.mjs'
import assert from '../lib/assert.mjs'
import { printError } from '../lib/cli.mjs'
let testsWereRun = false
function CreateT() {
const t = new c.Casette()
t.reporter = ''
return t
}
c.test('Casette describe should add prefix to the group tests', async function() {
testsWereRun = true
const assertPrefix = 'something'
const assertName = 'blabla'
const t = CreateT()
t.begin()
t.setFilename('test')
t.describe(assertPrefix, function() {
t.test(assertName, function() {})
})
assert.strictEqual(t.groupsFlat.length, 1)
assert.strictEqual(t.groupsFlat[0].tests.length, 1)
assert.strictEqual(t.groupsFlat[0].tests[0].name, assertPrefix + ' ' + assertName)
})
c.test('Casette describe should add prefix to individual tests', async function() {
testsWereRun = true
const assertPrefix = 'something'
const assertName = 'blabla'
const t = CreateT()
t.begin()
t.describe(assertPrefix, function() {
t.test(assertName, function() {})
})
assert.strictEqual(t.tests.length, 1)
assert.strictEqual(t.tests[0].name, assertPrefix + ' ' + assertName)
})
c.test('Casette describe should support multiple describe', async function() {
testsWereRun = true
const assertPrefix = 'something'
const assertPrefix2 = 'else'
const assertName = 'blabla'
const t = CreateT()
t.begin()
t.describe(assertPrefix, function() {
t.describe(assertPrefix2, function() {
t.test(assertName, function() {})
})
})
assert.strictEqual(t.tests.length, 1)
assert.strictEqual(t.tests[0].name, assertPrefix + ' ' + assertPrefix2 + ' ' + assertName)
})
c.test('Casette should run test', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.test('', function() {
assertIsTrue = true
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
c.test('Casette should run promised test', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.test('', function() {
return new Promise(function(res) {
assertIsTrue = true
res()
})
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
c.test('Casette should support callback', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.test('', function(cb) {
setTimeout(function() {
assertIsTrue = true
cb()
}, 50)
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
c.test('Casette should support directly thrown errors', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.test('', function() {
throw assertError
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
c.test('Casette should support promise rejected errors', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.test('', function() {
return new Promise(function(res, rej) {
rej(assertError)
})
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
c.test('Casette should support callback rejected errors', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.test('', function(cb) {
cb(assertError)
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
c.test('Casette should support timing out tests', async function() {
testsWereRun = true
const t = CreateT()
t.begin()
t.test('', function(cb) { }).timeout(50)
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /50ms/)
})
c.test('Casette should support timed out tests on late tests', async function() {
testsWereRun = true
const t = CreateT()
t.begin()
t.test('', function(cb) {
setTimeout(function() {
cb()
}, 100)
}).timeout(50)
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /50ms/)
})
c.test('Casette should support skipped tests', async function() {
testsWereRun = true
const t = CreateT()
t.begin()
t.test('', function() {
throw new Error('Should not be called')
}).skip()
await t.run()
assert.strictEqual(t.failedTests.length, 0)
})
// Extra testing to make sure tests were run at all
process.on('exit', function(e) {
try {
assert.strictEqual(testsWereRun, true)
} catch(err) {
printError(err)
process.exit(1)
}
process.exit(e)
})

265
test/cli.test.mjs Normal file
View file

@ -0,0 +1,265 @@
import c from '../lib/casette.mjs'
import assert from '../lib/assert.mjs'
import { CLI, getFiles, fileMatches } from '../lib/cli.mjs'
c.describe('CLI', function() {
let cli = new CLI()
c.test('#constructor() give default options', function() {
assert.strictEqual(cli.reporter, 'list')
assert.deepEqual(cli.targets, ['test/**'])
assert.deepEqual(cli.files, [])
assert.notOk(cli.errored)
})
/*****************************************
* #parseOptions()
*****************************************/
c.describe('#parseOptions()', function() {
c.test('should not do anything if no options', function() {
cli.reporter = 'list'
cli.parseOptions([])
assert.strictEqual(cli.reporter, 'list')
assert.notOk(cli.errored)
})
c.test('should support overriding reporter with shorthand option', function() {
cli.reporter = 'list'
cli.parseOptions(['-r', 'dot'])
assert.strictEqual(cli.reporter, 'dot')
assert.notOk(cli.errored)
})
c.test('should support overriding reporter with long option', function() {
cli.reporter = 'list'
cli.parseOptions(['--reporter', 'dot'])
assert.strictEqual(cli.reporter, 'dot')
assert.notOk(cli.errored)
})
c.test('should support reporter list', function() {
cli.reporter = 'list'
cli.parseOptions(['-r', 'list'])
assert.strictEqual(cli.reporter, 'list')
assert.notOk(cli.errored)
})
c.test('should mark errored if missing reporter', function() {
cli.parseOptions(['--reporter'])
assert.ok(cli.errored)
})
c.test('should mark errored if invalid reporter', function() {
cli.parseOptions(['--reporter', 'test'])
assert.ok(cli.errored)
})
c.test('should add file to targets', function() {
cli.parseOptions(['test'])
assert.deepEqual(cli.targets, ['test'])
assert.notOk(cli.errored)
})
c.test('should add file to targets no matter where it is', function() {
cli.parseOptions(['test', '-r', 'list', 'test2'])
assert.deepEqual(cli.targets, ['test', 'test2'])
assert.notOk(cli.errored)
})
c.test('should default add test to target if no target', function() {
cli.parseOptions(['-r', 'list'])
assert.deepEqual(cli.targets, ['test/**'])
assert.notOk(cli.errored)
})
})
/*****************************************
* #processTargets()
*****************************************/
c.describe('#processTargets()', function() {
c.test('should mark errored if empty', async function() {
cli.targets = ['test/folder1/*.txt']
await cli.processTargets()
assert.strictEqual(cli.files.length, 0)
assert.ok(cli.errored)
})
c.test('should support direct file path if exists', async function() {
cli.targets = ['test/folder1/sampletest1.temp.mjs']
await cli.processTargets()
assert.strictEqual(cli.files.length, 1)
assert.strictEqual(cli.files[0], 'test/folder1/sampletest1.temp.mjs')
})
c.test('should return all files in a directory', async function() {
cli.targets = ['test/folder1/']
await cli.processTargets()
assert.strictEqual(cli.files.length, 2)
assert.strictEqual(cli.files[0], 'test/folder1/sampletest1.temp.mjs')
assert.strictEqual(cli.files[1], 'test/folder1/sampletest2.temp.mjs')
})
c.test('should support start as folder substitute', async function() {
cli.targets = ['*/folder1/']
await cli.processTargets()
assert.strictEqual(cli.files.length, 2)
assert.strictEqual(cli.files[0], 'test/folder1/sampletest1.temp.mjs')
assert.strictEqual(cli.files[1], 'test/folder1/sampletest2.temp.mjs')
})
c.test('should support grabbing only files in folder', async function() {
cli.targets = ['test/*']
await cli.processTargets()
assert.ok(cli.files.length)
for (let i = 0; i < cli.files.length; i++) {
assert.notOk(cli.files[i].match(/\/folder1\//))
assert.notOk(cli.files[i].match(/\/folder2\//))
}
})
c.test('should support grabbing only pattern files in folder', async function() {
cli.targets = ['test/*.test.mjs']
await cli.processTargets()
assert.ok(cli.files.length)
for (let i = 0; i < cli.files.length; i++) {
assert.notOk(cli.files[i].match(/\/folder1\//))
assert.notOk(cli.files[i].match(/\/folder2\//))
}
})
c.test('should support multiple star pattern', async function() {
cli.targets = ['test/*/*.mjs']
await cli.processTargets()
assert.strictEqual(cli.files.length, 4)
cli.files.sort()
assert.deepEqual(cli.files, [
'test/folder1/sampletest1.temp.mjs',
'test/folder1/sampletest2.temp.mjs',
'test/folder2/sampletest3.temp.mjs',
'test/folder2/sampletest4.temp.mjs',
])
cli.targets = ['test/*/sampletest*.mjs']
await cli.processTargets()
assert.strictEqual(cli.files.length, 4)
cli.files.sort()
assert.deepEqual(cli.files, [
'test/folder1/sampletest1.temp.mjs',
'test/folder1/sampletest2.temp.mjs',
'test/folder2/sampletest3.temp.mjs',
'test/folder2/sampletest4.temp.mjs',
])
})
c.test('should support double star pattern', async function() {
cli.targets = ['test/**/*.mjs']
await cli.processTargets()
assert.ok(cli.files.length)
let found = {
sampletest1: false,
sampletest2: false,
sampletest3: false,
sampletest4: false,
sampletest5: false,
cli: false
}
for (let i = 0; i < cli.files.length; i++) {
if (cli.files[i] === 'test/folder1/sampletest1.temp.mjs') {
found.sampletest1 = true
}
if (cli.files[i] === 'test/folder1/sampletest2.temp.mjs') {
found.sampletest2 = true
}
if (cli.files[i] === 'test/folder2/sampletest3.temp.mjs') {
found.sampletest3 = true
}
if (cli.files[i] === 'test/folder2/sampletest4.temp.mjs') {
found.sampletest4 = true
}
if (cli.files[i] === 'test/folder2/sampletest5.temp.txt') {
found.sampletest5 = true
}
if (cli.files[i] === 'test/cli.test.mjs') {
found.cli = true
}
}
assert.deepEqual(found, {
sampletest1: true,
sampletest2: true,
sampletest3: true,
sampletest4: true,
sampletest5: false,
cli: true
})
})
c.test('should support double star pattern end', async function() {
cli.targets = ['test/**']
await cli.processTargets()
assert.ok(cli.files.length)
let found = {
sampletest1: false,
sampletest2: false,
sampletest3: false,
sampletest4: false,
sampletest5: false,
cli: false
}
for (let i = 0; i < cli.files.length; i++) {
if (cli.files[i] === 'test/folder1/sampletest1.temp.mjs') {
found.sampletest1 = true
}
if (cli.files[i] === 'test/folder1/sampletest2.temp.mjs') {
found.sampletest2 = true
}
if (cli.files[i] === 'test/folder2/sampletest3.temp.mjs') {
found.sampletest3 = true
}
if (cli.files[i] === 'test/folder2/sampletest4.temp.mjs') {
found.sampletest4 = true
}
if (cli.files[i] === 'test/folder2/sampletest5.temp.txt') {
found.sampletest5 = true
}
if (cli.files[i] === 'test/cli.test.mjs') {
found.cli = true
}
}
assert.deepEqual(found, {
sampletest1: true,
sampletest2: true,
sampletest3: true,
sampletest4: true,
sampletest5: true,
cli: true
})
})
})
})
c.test('#fileMatches() should support filename matching with glob pattern', async function() {
assert.ok(fileMatches('bla.test.mjs', '*.mjs'))
assert.ok(fileMatches('bla.test.mjs', '*test.mjs'))
assert.ok(fileMatches('bla.test.mjs', 'bla*.mjs'))
assert.notOk(fileMatches('bla.test.mjs', 'bla*.js'))
assert.notOk(fileMatches('bla.test.mjs', '*.js'))
assert.notOk(fileMatches('bla.test.mjs', 'blas*.js'))
})

View file

View file

View file

View file

View file

@ -0,0 +1 @@
keep

9
test/test.mjs Normal file
View file

@ -0,0 +1,9 @@
import { Casette as c, assert} from '../index.mjs'
c.describe('Array', function() {
c.describe('#indexOf()', function() {
c.test('should return -1 when value is not present', function() {
assert.equal([1,2,3].indexOf(4), -1)
})
})
})