[Pkg-javascript-commits] [node-tap] 45/186: mocha-like BDD DSL unit test
Bastien Roucariès
rouca at moszumanska.debian.org
Fri Dec 1 16:40:42 UTC 2017
This is an automated email from the git hooks/post-receive script.
rouca pushed a commit to branch master
in repository node-tap.
commit 1517575716e3c4fe2bd50c76551105a5e607bc17
Author: isaacs <i at izs.me>
Date: Sun Oct 29 22:27:57 2017 -0700
mocha-like BDD DSL unit test
---
lib/mocha.js | 167 ++++++++++++++++++++++++++-----------------------
lib/test.js | 15 ++---
test/test/mochalike.js | 3 +-
unit/mocha.js | 125 ++++++++++++++++++++++++++++++++++++
4 files changed, 222 insertions(+), 88 deletions(-)
diff --git a/lib/mocha.js b/lib/mocha.js
index c93c2a6..60e179c 100644
--- a/lib/mocha.js
+++ b/lib/mocha.js
@@ -1,133 +1,119 @@
'use strict'
-exports.it = exports.specify = it
-exports.context = exports.describe = describe
-exports.before = before
-exports.after = after
-exports.beforeEach = beforeEach
-exports.afterEach = afterEach
-
-exports.global = function () {
- Object.keys(exports).forEach(function (g) {
- global[g] = exports[g]
- })
-}
-
const t = require('./tap.js')
t.jobs = 1
const tapStack = [ t ]
let level = 0
const suiteStack = []
-function describe (name, fn) {
- new Suite(name, fn)
-}
+const describe = (name, fn, opt) =>
+ new Suite(name, fn, opt)
-function Suite (name, fn) {
- this.parent = suiteStack[ suiteStack.length - 1 ]
- if (typeof name === 'function')
- fn = name, name = null
- if (fn && fn.name && !name)
- name = fn.name
- this.todo = !fn
- this.fn = fn
- this.name = name
- this.after = []
- this.test = null
+class Suite {
+ constructor (name, fn, opt) {
+ this.parent = suiteStack[ suiteStack.length - 1 ]
+ if (typeof name === 'function')
+ fn = name, name = null
+ if (fn && fn.name && !name)
+ name = fn.name
+ this.options = opt || {}
+ this.options.todo = this.options.todo || !fn
+ this.fn = fn
+ this.name = name
+ this.after = []
+ this.test = null
- this.run()
-}
+ this.run()
+ }
-Suite.prototype.run = function () {
- const t = tapStack[ tapStack.length - 1 ]
- t.test(this.name, { todo: this.todo }, function (tt) {
- this.test = tt
- tapStack.push(tt)
- suiteStack.push(this)
- const ret = this.fn()
- this.runAfter()
- suiteStack.pop()
- return ret
- }.bind(this))
-}
+ run () {
+ const t = tapStack[ tapStack.length - 1 ]
+ t.test(this.name, this.options, tt => {
+ this.test = tt
+ tapStack.push(tt)
+ suiteStack.push(this)
+ const ret = this.fn()
+ this.runAfter()
+ suiteStack.pop()
+ return ret
+ })
+ }
-Suite.prototype.runAfter = function () {
- this.after.forEach(function (namefn) {
- const name = namefn[0]
- const fn = namefn[1]
- before(name, fn)
- })
- let t
- do {
- t = tapStack.pop()
- } while (t && t !== this.test)
- if (this.test && !this.test.results)
- t.end()
+ runAfter () {
+ this.after.forEach(a =>
+ before(a[0], a[1], a[2]))
+ let t
+ do {
+ t = tapStack.pop()
+ } while (t && t !== this.test)
+ if (this.test && !this.test.results)
+ t.end()
+ }
}
-function before (name, fn) {
+const before = (name, fn, options) => {
if (typeof name === 'function')
fn = name, name = null
if (fn && fn.name && !name)
name = fn.name
+ options = options || {}
const todo = !fn
+ options.todo = options.todo || todo
+ options.silent = true
const suite = suiteStack[ suiteStack.length - 1 ]
+ if (!suite)
+ throw new Error('cannot call "before" outside of describe()')
const t = tapStack[ tapStack.length - 1 ]
if (!name)
name = ''
- t.test(name, { todo: todo, silent: true }, function (tt) {
+
+ const done = tt => er => er ? tt.threw(er) : tt.end()
+ t.test(name, options, tt => {
const ret = fn.call(suite, done(tt))
if (!ret && fn.length === 0)
tt.end()
else
return ret
})
-
- function done (tt) { return function (er) {
- if (er)
- tt.threw(er)
- else
- tt.end()
- }}
}
-function it (name, fn) {
+const it = (name, fn, options) => {
if (typeof name === 'function')
fn = name, name = null
if (fn && fn.name && !name)
name = fn.name
+ options = options || {}
const todo = !fn
const suite = suiteStack[ suiteStack.length - 1 ]
const t = tapStack[ tapStack.length - 1 ]
if (!name)
name = ''
- t.test(name, { todo: todo, tapMochaTest: true }, function (tt) {
+
+ const done = tt => er => er ? tt.threw(er) : tt.end()
+ options.todo = options.todo || todo
+ options.tapMochaTest = true
+ t.test(name, options, tt => {
const ret = fn.call(tt, done(tt))
if (ret && ret.then)
return ret
else if (fn.length === 0)
tt.end()
})
-
- function done (tt) { return function (er) {
- if (er)
- tt.threw(er)
- else
- tt.end()
- }}
}
-function after (name, fn) {
+it.skip = (name, fn) => it(name, fn, { skip: true })
+it.todo = (name, fn) => it(name, fn, { todo: true })
+
+function after (name, fn, options) {
const suite = suiteStack[ suiteStack.length - 1 ]
if (!suite)
throw new Error('cannot call "after" outside of describe()')
- if (fn)
- suite.after.push([name, fn])
- else
- suite.after.push([name])
+ suite.after.push([name, fn, options])
}
function moment (when, fn) {
const t = tapStack[ tapStack.length - 1 ]
+ // need function because 'this' tells us which tap object
+ // has the tapMochaTest thing in its options object
t[when](function (cb) {
if (!this.options.tapMochaTest)
return cb()
@@ -140,10 +126,33 @@ function moment (when, fn) {
})
}
-function beforeEach (fn) {
+const beforeEach = fn =>
moment('beforeEach', fn)
-}
-function afterEach (fn) {
+const afterEach = fn =>
moment('afterEach', fn)
+
+exports.it = exports.specify = it
+exports.context = exports.describe = describe
+exports.before = before
+exports.after = after
+exports.beforeEach = beforeEach
+exports.afterEach = afterEach
+
+let saved
+exports.global = _ => {
+ if (!saved)
+ saved = new Map()
+
+ Object.keys(exports).filter(g => g !== 'global').forEach(g => {
+ if (!saved.has(g))
+ saved.set(g, global[g])
+ global[g] = exports[g]
+ })
}
+
+exports.deglobal = _ =>
+ Object.keys(exports).filter(g => g !== 'global').forEach(g => {
+ if (saved && saved.has(g))
+ global[g] = saved.get(g)
+ })
diff --git a/lib/test.js b/lib/test.js
index 47c5e18..d92938a 100644
--- a/lib/test.js
+++ b/lib/test.js
@@ -301,9 +301,8 @@ class Test extends Base {
if (this.bailedOut)
this.onbufferedend(p)
else
- this.runBeforeEach(p,
- p.main.bind(p,
- this.onbufferedend.bind(this, p)))
+ this.runBeforeEach(p, () =>
+ p.main(() => this.onbufferedend(p)))
}
this.debug('done processing', this.queue, this.occupied)
@@ -325,10 +324,9 @@ class Test extends Base {
return this.onindentedend(p)
this.debug(' > subtest indented')
p.pipe(this.parser, { end: false })
- this.runBeforeEach(p,
- this.writeSubComment.bind(this, p,
- p.main.bind(p,
- this.onindentedend.bind(this, p))))
+ this.runBeforeEach(p, () =>
+ this.writeSubComment(p, () =>
+ p.main(() => this.onindentedend(p))))
} else if (p.readyToProcess) {
this.debug(' > subtest buffered, finished')
// finished! do the thing!
@@ -475,6 +473,9 @@ class Test extends Base {
extra = extra || {}
+ if (extra.expectFail)
+ ok = !ok
+
if (this.assertAt) {
extra.at = this.assertAt
this.assertAt = null
diff --git a/test/test/mochalike.js b/test/test/mochalike.js
index 76f777f..f93e755 100644
--- a/test/test/mochalike.js
+++ b/test/test/mochalike.js
@@ -1,6 +1,5 @@
if (typeof describe !== 'function') {
- var t = require('../..')
- t.mochaGlobals()
+ require('../../lib/mocha.js').global()
}
/* global describe, it */
diff --git a/unit/mocha.js b/unit/mocha.js
new file mode 100644
index 0000000..203be75
--- /dev/null
+++ b/unit/mocha.js
@@ -0,0 +1,125 @@
+'use strict'
+const mocha = require('../lib/mocha.js')
+const assert = require('assert')
+
+mocha.describe('globals', () => {
+ let beforeEaches = 0
+ mocha.beforeEach(() => beforeEaches++)
+
+ mocha.beforeEach(cb => setTimeout(cb))
+ mocha.beforeEach(() => new Promise(r => r()))
+
+ let afterEaches = 0
+ mocha.afterEach(() => afterEaches++)
+
+ // test that afterEach is happening correct number
+ // of times.
+ let eachExpect = 0
+ mocha.afterEach(() => new Promise(res => {
+ eachExpect ++
+ assert.equal(beforeEaches, eachExpect, 'before')
+ assert.equal(afterEaches, eachExpect, 'after')
+ res()
+ }))
+
+ mocha.it('has no describe', () =>
+ assert.equal(global.describe, undefined))
+
+ mocha.it('is ok running deglobal() first', () => {
+ mocha.deglobal()
+ assert.equal(global.describe, undefined)
+ })
+
+ mocha.it('has describe after call', () => {
+ mocha.global()
+ mocha.global()
+ assert.equal(global.describe, mocha.describe)
+ })
+
+ mocha.it('has no describe after deglobal', () => {
+ deglobal()
+ assert.equal(global.describe, undefined)
+ })
+
+ mocha.it('escape to tap', function () {
+ const t = this
+ t.test('should not get a beforeEach', t =>
+ t.test('or an after each', t => {
+ t.pass('this is fine')
+ t.end()
+ }))
+ })
+
+ // at this point, beforeEach has been called
+ // 1 more time than afterEach
+ mocha.it('called beforeEach/afterEach', () =>
+ new Promise((resolve) => {
+ assert.equal(beforeEaches, eachExpect + 1)
+ assert.equal(afterEaches, eachExpect)
+ resolve()
+ }))
+})
+
+assert.throws(_ => mocha.after(),
+ 'cannot call "after" outside of describe()')
+assert.throws(_ => mocha.before(),
+ 'cannot call "before" outside of describe()')
+
+let calledAfter = false
+let calledBefore = false
+mocha.describe(function after_and_before () {
+ mocha.before((cb) => {
+ assert.equal(calledBefore, false)
+ calledBefore = true
+ setTimeout(cb)
+ })
+ mocha.before('named before', () => new Promise(r => {
+ assert.equal(calledBefore, true)
+ r()
+ }))
+
+ mocha.after(() => {
+ assert.equal(calledAfter, false)
+ calledAfter = true
+ })
+
+ mocha.after('named after', () => {
+ assert.equal(calledAfter, true)
+ })
+
+ mocha.after(function named_after () {
+ assert.equal(calledAfter, true)
+ })
+
+ mocha.it(function this_is_fine () {})
+ mocha.it(() => {})
+ mocha.it(cb => cb())
+})
+mocha.describe('after after', function () {
+ this.test.plan(1)
+ mocha.it('should have called after fn', () =>
+ assert.equal(calledAfter, true))
+})
+
+mocha.describe('todo, skip, and failure', () => {
+ let calledTodoFn = false
+ let calledSkipFn = false
+ const it = mocha.it
+ mocha.describe('expect todo and skip', function () {
+ /* istanbul ignore next */
+ it.todo('expected todo', () => calledTodoFn = true)
+ /* istanbul ignore next */
+ it.skip('expected skip', () => calledSkipFn = true)
+ }, { silent: true })
+ it('expected fail from cb(er)', cb => {
+ cb(new Error('expected failure'))
+ }, { expectFail: true })
+ it('did not call skip/todo functions', () => {
+ assert.equal(calledTodoFn, false)
+ assert.equal(calledSkipFn, false)
+ })
+})
+
+mocha.describe('expected before failure', () =>
+ mocha.before('expect failure', (cb) =>
+ cb(new Error('expected')), { expectFail : true }))
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-tap.git
More information about the Pkg-javascript-commits
mailing list