-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
v1 #12
Comments
Sort of... It's almost done, really :D It's amazing how minimal is and what it can do. /*!
* mukla <https://github.com/tunnckoCore/mukla>
*
* Copyright (c) Charlike Mike Reagent <@tunnckoCore> (http://i.am.charlike.online)
* Released under the MIT license.
*/
'use strict'
var getFnName = require('get-fn-name')
var MiniBase = require('minibase').MiniBase
var results = require('minibase-results')
var flow = require('minibase-control-flow')
var isAsyncFn = require('is-async-function')
function Mukla (options) {
if (!(this instanceof Mukla)) {
return new Mukla(options)
}
MiniBase.call(this, options)
this.use(results()) // @TODO: remove `through2`
this.use(flow())
this.testNames = []
}
MiniBase.extend(Mukla)
Mukla.prototype.addTest = function addTest (title, fn) {
if (typeof title === 'function') {
fn = title
title = null
}
if (typeof fn !== 'function') {
throw new TypeError('.addTest: expect `fn` to be a function')
}
title = typeof title === 'string' ? title : getFnName(fn)
if (title === null) {
this.stats.anonymous = this.stats.anonymous + 1
}
title = title || '(unnamed test ' + this.stats.anonymous + ')'
fn.hasCb = isAsyncFn(fn)
this.testNames.push(title)
this.tests.push(fn)
this.stats.count++
return this
}
Mukla.prototype.run = function run (done) {
done = typeof done === 'function' ? done : function noop () {}
var self = this
var reporter = typeof this.options.reporter === 'function'
? this.options.reporter
: defaultReporter
reporter.call(this, this)
this.each(this.tests, this.options, {
// @TODO: update `each-promise` to use try-catch-core
// context: this.testContext,
start: function () {
self.emit('start')
},
beforeEach: function (item, index, arr) {
self.emit('beforeEach', item, index, arr)
},
afterEach: function (item, index, arr) {
self.stats.runned++
self.emit('afterEach', item, index, arr)
var fn = arr[index]
var test = {
fn: fn,
hasCb: fn.hasCb,
reason: item.reason,
value: item.value,
index: item.index,
title: self.testNames[index],
tests: arr
}
if (item.reason) {
self.stats.fail++
return self.emit('fail', test, test.index + 1)
}
console.log(fn.hasCb)
// @TODO: update `each-promise` to use try-catch-core
if (fn.hasCb && item.value) {
var msg = ' must not return anything, it has `done` argument'
test.reason = new Error('test ' + (test.index + 1) + msg)
self.stats.fail++
return self.emit('fail', test, test.index + 1)
}
if (!fn.hasCb && !item.value) {
var msg = ' must return, it has not `done` argument'
test.reason = new Error('test ' + (test.index + 1) + msg)
self.stats.fail++
return self.emit('fail', test, test.index + 1)
}
self.stats.pass++
self.emit('pass', test, index + 1)
},
finish: function (err, res) {
self.emit('finish', err, res, done)
}
}).catch(done)
}
function defaultReporter () {
this
.once('start', function () {
console.log('TAP version 13')
console.log('1..' + this.stats.count)
})
.on('pass', function (test, idx) {
console.log('ok', idx, test.title)
})
.on('fail', function (test, idx) {
console.log('not ok', idx, test.title, test.reason.toString())
})
.once('finish', function (err, res, done) {
if (!done) return console.log('done')
if (err) return done(err)
done(null, res)
})
}
/**
* example usage
*/
var delay = require('delay')
var fixtureTwo = function () {
return [
() => delay(900).then(() => 1),
() => delay(770).then(() => { throw new Error('foo') }),
() => delay(620).then(() => 3),
() => delay(800).then(() => {}),
() => delay(700).then(() => 5),
(cb) => {
}
]
}
var app = Mukla(/*{ serial: true }*/)
fixtureTwo().forEach(function (fn) {
app.addTest(fn)
})
app.run(console.log) |
blocked by |
Rolldown CLI is needed too, so we'll have Mukla CLI that transpiles ESM. |
gruu/mukla/asia/testup/voala, using const getFnName = require('get-fn-name')
const pMap = require('p-map')
const mitt = require('./mitt')
function defaultReporter () {
const emitter = mitt()
emitter
.on('start', ({ stats }) => {
console.log('TAP version 13')
console.log(`1..${stats.count}`)
})
.on('afterEach', ({ test }) => {
if (test.reason) {
console.log('not ok', test.index, test.title, test.reason.toString())
} else {
console.log('ok', test.index, test.title)
}
})
.on('finish', ({ reason, stats }) => {
if (reason) {
console.log('# NOT OK', stats)
process.exit(1)
} else {
console.log('# OK', stats)
process.exit(0)
}
// console.log('# OK', stats)
// process.exit(0)
})
return emitter
}
function handleFn (fn, opts) {
return new opts.Promise(function (resolve, reject) {
var called = false
function done (e, res) {
called = true
if (e) return reject(e)
if (res instanceof Error) {
return reject(res)
}
return resolve(res)
}
var args = utils.arrayify(opts.args)
args = fn.length ? args.concat(done) : args
var ret = fn.apply(opts.context, args)
if (!called) {
ret instanceof Error
? reject(ret)
: resolve(ret)
}
})
}
function testup (options) {
options = Object.assign({}, options)
const app = {
stats: {
anonymous: 0,
count: 0,
fail: 0,
pass: 0
},
options: options,
tests: [],
addTest: (title, fn) => {
if (typeof title === 'function') {
fn = title
title = null
}
if (typeof fn !== 'function') {
throw new TypeError('.addTest: expect `fn` to be a function')
}
title = typeof title === 'string' ? title : getFnName(fn)
if (title === null) {
app.stats.anonymous = app.stats.anonymous + 1
}
app.stats.count++
app.tests.push({
title: title || `(unnamed test ${app.stats.anonymous})`,
index: app.stats.count,
fn: fn
})
return app
},
addReporter: (fn) => {
app.reporter = fn()
return app.reporter
},
run: (opts) => {
app.options = Object.assign({}, app.options, opts)
if (typeof app.reporter !== 'function') {
app.reporter = app.addReporter(defaultReporter)
}
app.reporter.emit('start', { stats: app.stats })
const mapper = (test) => {
app.reporter.emit('beforeEach', { test: test, stats: app.stats })
return handleFn(test.fn, app.options)
.then((val) => {
test.value = val
app.stats.pass++
app.reporter.emit('afterEach', { test: test, stats: app.stats })
return val
})
.catch((er) => {
test.reason = er
app.stats.fail++
app.reporter.emit('afterEach', { test: test, stats: app.stats })
throw er
})
}
return pMap(app.tests, mapper, app.options).then(() => {
app.reporter.emit('finish', { stats: app.stats })
}, (err) => {
app.reporter.emit('finish', { reason: err, stats: app.stats })
})
}
}
return app
}
/**
* EXAMPLE
*/
var delay = require('delay')
var assert = require('assert')
const runner = testup()
setTimeout(() => {
runner.run()
}, 0)
runner.addTest('foo bar baz', function () {
assert.strictEqual(1, 1)
})
runner.addTest('quxie setty', function () {
return delay(400).then(() => {
assert.strictEqual(2222, 222)
})
})
runner.addTest('zeta gama', function () {
sasa.strictEqual(3, 3)
})
runner.addTest('hiahahah zeah', function () {
assert.strictEqual(3, 3)
}) |
So, let's finalize it? Mukla v1 - minibase + each-promise (possibly node<4, through |
backup minibase v2 and test runner minibase 'use strict'
var dush = require('dush')
var dushOptions = require('dush-options')
var dushBetterUse = require('dush-better-use')
/**
* dush plugins
*/
var redolent = require('redolent')
var mixinDeep = require('mixin-deep')
var createPlugin = require('minibase-create-plugin')
var dushPlugins = createPlugin('dush-plugins', function (app, opts) {
app.options = mixinDeep({}, app.options, opts)
app.use(dushBetterUse())
app.define('run', function run (a, b, c) {
var args = [].slice.call(arguments)
var resolve = redolent(function resolver () {
app.emit('start', app)
}, app.options)
return app._plugins
.reduce(reducer(app, args), resolve())
.then(function () {
app.emit('finish', app)
})
.catch(function (err) {
app.emit('error', err)
app.emit('finish', app)
})
})
return app
})
function reducer (app, args) {
return function reducer (promise, handler) {
return promise.then(function () {
app.emit('beforeEach', app, handler, args)
return redolent(handler, {
Promise: app.options.Promise,
context: app.options.context || handler,
args: args
})()
.then(function (res) {
handler.value = res
app.emit('afterEach', app, handler)
})
.catch(function (err) {
handler.reason = err
app.emit('afterEach', app, handler)
})
})
}
}
/**
* MiniBase v2
*/
function MiniBase (opts) {
return dush()
.use(dushOptions(opts))
.use((app) => {
app._plugins = []
app.addTest = (title, fnc) => {
fnc.title = title
fnc.index = app._plugins.length + 1
app._plugins.push(fnc)
return app
}
})
.use((app) => {
app.on('afterEach', (app, test) => {
if (test.reason) {
app.options.stats.count++
app.options.stats.fail++
app.emit('fail', app, test)
} else {
app.options.stats.count++
app.options.stats.pass++
app.emit('pass', app, test)
}
})
})
.use(dushBetterUse())
.use(dushPlugins())
}
module.exports = MiniBase runner 'use strict'
var minibase = require('./minibase')
var tapReport = require('dush-tap-report')
var extend = require('extend-shallow')
var assert = require('assert')
function Mukla (opts) {
return minibase(opts).use(
tapReport({
stats: {
count: 0,
pass: 0,
fail: 0
}
})
)
}
var app = Mukla({
relativePaths: false // strange bug when `true`
})
function test (title, fn) {
if (title && typeof title === 'object') {
app.options = extend({}, app.options, title)
} else {
app.addTest(title, fn)
}
return test
}
setTimeout(function () {
var done = function done (er) {
return new Promise(function (resolve, reject) {
if (er) return reject(er)
resolve()
})
}
// passed to each test function
// backward compatible: passes `done` function
// that has `assert` methods on it too
var param = extend(done, assert)
app.run(param).then(() => {
if (process && process.versions['electron']) {
window.close()
}
})
}, 0)
module.exports = extend(test, app, assert) |
Damn.. Love myself when document everything 🍡 |
Oh hell yea, but in current times it starting to lose more and more sense. Anyway, there is pretty stable implementation at I'm not sure with what and when I will finally come up. But it was a wild ride through the years. A lot of experiments and learned things. |
Yep. After 3 years out, i read that thing yet again :D |
Let's start it. We have pretty stable libs already. Also it currently silently hides tests that do not call the callback/done. It just normal with this architecture.
So let's clarify what will happen for v1 and what will be the diffs with
gruu
andasia
. At least for me.mukla v1
gruu v1
t
argument, where you will find that assertion methodst
argument is object that contains all assert/core-assert methods plus more and will havet.context
property object for sharing context between tests (useful when you use arrow functions)this
context of the test function will be same ast
, sothis.context === t.context
mukla/assertit
asia v1
gruu
)t
argumentmukla/assertit
gruu v1
and almost compatible with it, plus moreThe text was updated successfully, but these errors were encountered: