-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathserver.js
127 lines (109 loc) · 4.2 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
123
124
125
126
127
var Mocha = Npm.require("mocha");
var Fiber = Npm.require("fibers");
setupGlobals = function(mocha){
//basically a direct copy from meteor/packages/meteor/dynamics_nodejs.js
//except the wrapped function has an argument (mocha distinguishes
//asynchronous tests from synchronous ones by the "length" of the
//function passed into it, before, etc.)
var moddedBindEnvironment = function (func, onException, _this) {
Meteor._nodeCodeMustBeInFiber();
var boundValues = _.clone(Fiber.current._meteor_dynamics || []);
if (!onException || typeof(onException) === 'string') {
var description = onException || "callback of async function";
onException = function (error) {
Meteor._debug(
"Exception in " + description + ":",
error && error.stack || error
);
};
}
//IMPORTANT note the callback variable present here, for
//Metoer.bindEnvironment this is ` return function (/* arguments */) {`
return function (callback) {
var args = _.toArray(arguments);
var runWithEnvironment = function () {
var savedValues = Fiber.current._meteor_dynamics;
try {
// Need to clone boundValues in case two fibers invoke this
// function at the same time
Fiber.current._meteor_dynamics = _.clone(boundValues);
var ret = func.apply(_this, args);
} catch (e) {
onException(e);
} finally {
Fiber.current._meteor_dynamics = savedValues;
}
return ret;
};
if (Fiber.current)
return runWithEnvironment();
Fiber(runWithEnvironment).run();
};
};
var mochaExports = {};
mocha.suite.emit("pre-require", mochaExports, undefined, mocha);
//console.log(mochaExports);
// 1. patch up describe function so it plays nice w/ fibers
// 2. trick to allow binding the suite instance as `this` value
// inside of describe blocks, to allow e.g. to set custom timeouts.
function wrapRunnable(func) {
return function() {
// `this` will be bound to the suite instance, as of Mocha's `describe` implementation
Meteor.bindEnvironment(func.bind(this), function(err) { throw err; })();
}
}
global.describe = function (name, func){
return mochaExports.describe(name, wrapRunnable(func));
};
global.describe.skip = mochaExports.describe.skip;
global.describe.only = function(name, func) {
mochaExports.describe.only(name, Meteor.bindEnvironment(func, function(err){ throw err; }));
};
//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 moddedBindEnivronment function described above instead
//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.
global['it'] = function (name, func){
wrappedFunc = function(callback){
if (func.length == 0){
func();
callback();
}
else {
func(callback);
}
}
boundWrappedFunction = moddedBindEnvironment(wrappedFunc, function(err){
throw err;
});
mochaExports['it'](name, boundWrappedFunction);
};
global.it.skip = mochaExports.it.skip;
global.it.only = function(name, func) {
mochaExports.it.only(name, Meteor.bindEnvironment(func, function(err){ throw err; }));
};
["before", "beforeEach", "after", "afterEach"].forEach(function(testFunctionName){
global[testFunctionName] = function (func){
wrappedFunc = function(callback){
if (func.length == 0){
func();
callback();
}
else {
func(callback);
}
}
boundWrappedFunction = moddedBindEnvironment(wrappedFunc, function(err){
throw err;
});
mochaExports[testFunctionName](boundWrappedFunction);
}
});
}