1 | 'use strict';
|
2 |
|
3 | var config = require('./config');
|
4 | var EventEmitter = require('events').EventEmitter;
|
5 |
|
6 | function TestNode(description, fn) {
|
7 | EventEmitter.call(this);
|
8 |
|
9 | this.description = description;
|
10 | this.fn = fn;
|
11 | }
|
12 |
|
13 | TestNode.prototype = Object.create(EventEmitter.prototype);
|
14 | TestNode.prototype.constructor = TestNode;
|
15 |
|
16 | TestNode.prototype.hasRun = false;
|
17 |
|
18 | function verifyCanAssert(node) {
|
19 | if (node.hasRun)
|
20 | node.emit('error', 'TestNode has already completed ' +
|
21 | 'execution and cannot emit more assertions. Did you ' +
|
22 | 'forget a call to `t.cb(...)`?');
|
23 |
|
24 | return !node.hasRun;
|
25 | }
|
26 |
|
27 | TestNode.prototype._assertOk = function (args) {
|
28 | if (verifyCanAssert(this))
|
29 | this.emit('assertOk', args);
|
30 | };
|
31 |
|
32 | TestNode.prototype._assertNotOk = function (args) {
|
33 | if (verifyCanAssert(this))
|
34 | this.emit('assertNotOk', args);
|
35 | };
|
36 |
|
37 | TestNode.prototype.run = function () {
|
38 | var self = this;
|
39 |
|
40 | var done = false, pending = 0;
|
41 |
|
42 | function queueCallback(fn) {
|
43 | pending++;
|
44 | return function () {
|
45 | if (fn)
|
46 | runFn.call(this, fn, arguments);
|
47 |
|
48 | if (--pending === 0 && done)
|
49 | onNodeDone();
|
50 | }
|
51 | }
|
52 |
|
53 | function runFn(fn, args) {
|
54 | try {
|
55 | var result = fn.apply(this, args);
|
56 |
|
57 | if (result && typeof result.then === 'function' && !config.disablePromises) {
|
58 | pending++;
|
59 |
|
60 | result.then(function () {
|
61 | if (--pending === 0 && done)
|
62 | onNodeDone();
|
63 | }, function (err) {
|
64 | self._assertNotOk(err);
|
65 |
|
66 | if (--pending === 0 && done)
|
67 | onNodeDone();
|
68 | });
|
69 | }
|
70 |
|
71 | } catch (err) {
|
72 | self._assertNotOk(err);
|
73 | }
|
74 | }
|
75 |
|
76 | var queue = [];
|
77 |
|
78 | function runQueue() {
|
79 | if (queue.length === 0) {
|
80 | self.emit('treeDone');
|
81 | self.removeAllListeners();
|
82 | } else {
|
83 | var node = queue.shift();
|
84 |
|
85 | node.once('treeDone', runQueue);
|
86 | self.emit('childTest', node);
|
87 | node.run();
|
88 | }
|
89 | }
|
90 |
|
91 | function onNodeDone() {
|
92 | self.emit('nodeDone');
|
93 | runQueue();
|
94 | }
|
95 |
|
96 | var t = config.createAssertionWrapper(this._assertOk.bind(this), this._assertNotOk.bind(this));
|
97 |
|
98 | t.test = function (description, fn) { queue.push(new TestNode(description, fn)); };
|
99 | t.xtest = function (description) { queue.push(new SkipTestNode(description)); };
|
100 | t.comment = function () { self.emit('comment', arguments); };
|
101 |
|
102 | t.cb = queueCallback;
|
103 |
|
104 | this.emit('run');
|
105 | runFn(this.fn, [t]);
|
106 |
|
107 | done = true;
|
108 | if (pending === 0)
|
109 | onNodeDone();
|
110 | };
|
111 |
|
112 | function SkipTestNode(description) {
|
113 | TestNode.call(this, description);
|
114 | }
|
115 |
|
116 | SkipTestNode.prototype = Object.create(TestNode.prototype);
|
117 | SkipTestNode.prototype.constructor = SkipTestNode;
|
118 |
|
119 | SkipTestNode.prototype.skip = true;
|
120 |
|
121 | SkipTestNode.prototype.run = function () {
|
122 | this.emit('run');
|
123 | this.hasRun = true;
|
124 | this.emit('nodeDone');
|
125 | this.emit('treeDone');
|
126 | };
|
127 |
|
128 | module.exports = TestNode; |
\ | No newline at end of file |