forked from practicalmeteor/meteor-mocha-core
-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
server.js
executable file
·122 lines (108 loc) · 3.89 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import './setup'
import './cleanup'
import Mocha from 'mocha'
import config from './loadConfig'
import { Meteor } from 'meteor/meteor'
function setupGlobals (mocha) {
const mochaExports = {}
mocha.suite.emit('pre-require', mochaExports, undefined, mocha)
// 1. patch up it and hooks functions so it plays nice w/ fibers
// 2. trick to allow binding the suite instance as `this` value
// inside of suites blocks, to allow e.g. to set custom timeouts.
const wrapRunnable = function (fn) {
// In Meteor, these blocks will all be invoking Meteor code and must
// run within a fiber. We must therefore wrap each with something like
// bindEnvironment. The function passed off to mocha must have length
// greater than zero if we want mocha to run it asynchronously. That's
// why it uses the Fibers
// We're actually having mocha run all tests asynchronously. This
// is because mocha cannot tell when a synchronous fiber test has
// finished, because the test runner runs outside a fiber.
// It is possible that the mocha test runner could be run from within a
// fiber, but it was unclear to me how that could be done without
// forking mocha itself.
const wrappedFunction = function (done) {
const self = this._runnable
const run = function () {
try {
// Sync call
if (fn.length === 0) {
const result = fn.call(self)
if (result && typeof result.then === 'function') {
self.resetTimeout()
result
.then(function () {
done()
// Return null so libraries like bluebird do not warn about
// subsequently constructed Promises.
return null
},
function (reason) {
done(reason || new Error('Promise rejected with no or falsy reason'))
})
} else {
if (self.asyncOnly) {
return done(new Error('--async-only option in use without declaring `done()` or returning a promise'))
}
done()
}
} else {
fn.call(self, done)
}
} catch (error) {
done(error)
}
}
if (Meteor.isFibersDisabled) {
return run()
} else {
// pre-3.0 compatibility
const Fiber = require('fibers')
if (Fiber.current) return run()
Fiber(run).run()
}
}
// Show original function source code
wrappedFunction.toString = function () { return fn.toString() }
return wrappedFunction
}
mochaExports.__org_it = mochaExports.it
mochaExports.it = function (name, func) {
// You can create pending tests without a function
// http://mochajs.org/#pending-tests
// i.e pending test
// it('this is a pending test');
if (func) {
func = wrapRunnable(func)
}
return mochaExports.__org_it(name, func)
}
mochaExports.it.skip = mochaExports.__org_it.skip
mochaExports.it.only = (name, func) => {
mochaExports.__org_it.only(name, func)
}
const hooks = ['before', 'beforeEach', 'after', 'afterEach']
hooks.forEach((hook) => {
mochaExports[`__org_${hook}`] = mochaExports[hook]
mochaExports[hook] = (func) => {
return mochaExports[`__org_${hook}`](wrapRunnable(func))
}
})
Object.keys(mochaExports).forEach((key) => {
// We don't want original function to be export to global namespace
if (key.indexOf('__org_') > -1 || key.indexOf('run') > -1) {
return
}
global[key] = mochaExports[key]
})
}
// Initialize a new `Mocha` test runner instance that test driver packages
// can use to ensure they work well with other test driver packages.
const options = {
ui: 'bdd',
ignoreLeaks: true,
...config
}
const mochaInstance = new Mocha(options)
setupGlobals(mochaInstance)
export { mochaInstance, setupGlobals, Mocha }