UNPKG

6.2 kBJavaScriptView Raw
1'use strict';
2
3// Load modules
4
5const Hoek = require('hoek');
6const Coverage = require('./coverage');
7const Leaks = require('./leaks');
8const Runner = require('./runner');
9const Utils = require('./utils');
10
11
12// Declare internals
13
14const internals = {};
15
16
17// Exports
18
19exports.report = Runner.report;
20
21exports.execute = Runner.execute;
22
23exports.coverage = Coverage;
24
25exports.leaks = Leaks;
26
27exports.assertions = null; // Set by the -a command line option
28
29
30/*
31 experiment('Utilities', () => {
32
33 experiment('#isEven()', () => {
34
35 test('returns true on even values', () => {
36
37 });
38
39 test('returns false on odd values', () => {
40
41 });
42 });
43 });
44 */
45
46
47exports.script = function (options) {
48
49 options = options || {};
50
51 global._labScriptRun = true; // Compared by CLI to detect missing exports.lab
52
53 const script = {
54 _current: {
55 experiments: [],
56 tests: [],
57 options: {},
58 title: 'script'
59 },
60 _titles: [],
61 _path: [],
62 _count: 0,
63 _executed: false,
64 _onlyNodes: [],
65 _cli: options.cli,
66 setOnly: function (experiment, test, path) {
67
68 this._onlyNodes.push({ experiment, test, path });
69 }
70 };
71
72 script._root = script._current;
73
74 script.experiment = internals.experiment.bind(script);
75 script.experiment.skip = internals.skip(script, 'experiment');
76 script.experiment.only = internals.only(script, 'experiment');
77 script.describe = script.experiment;
78 script.suite = script.experiment;
79
80 script.test = internals.test.bind(script);
81 script.test.skip = internals.skip(script, 'test');
82 script.test.only = internals.only(script, 'test');
83 script.it = script.test;
84
85 script.before = internals.before.bind(script);
86 script.beforeEach = internals.beforeEach.bind(script);
87 script.after = internals.after.bind(script);
88 script.afterEach = internals.afterEach.bind(script);
89
90 if (exports.assertions) {
91 script.expect = exports.assertions.expect;
92 script.fail = exports.assertions.fail;
93 }
94
95 if (options.schedule !== false) { // Defaults to true
96 setImmediate(() => {
97
98 if (!script._executed) {
99 Runner.report(script, options); // Schedule automatic execution when used without the CLI
100 }
101 });
102 }
103
104 return script;
105};
106
107
108internals.experiment = function (title, options, fn) {
109
110 if (arguments.length !== 3) {
111 fn = options;
112 options = {};
113 }
114
115 const settings = Utils.mergeOptions(this._current.options, options, ['only']);
116
117 const child = {
118 title,
119 parent: this._current,
120 experiments: [],
121 tests: [],
122 options: settings
123 };
124
125 this._current.experiments.push(child);
126 this._current = child;
127
128 this._titles.push(title);
129 this._path = this._titles.concat(); // Clone
130
131 if (settings.only) {
132 this.setOnly(child, null, this._path);
133 }
134
135 fn.call(null); // eslint-disable-line no-useless-call
136
137 this._titles.pop();
138 this._path = this._titles.concat(); // Clone
139
140 this._current = child.parent;
141};
142
143
144internals.before = function (options, fn) {
145
146 if (arguments.length !== 2) {
147 fn = options;
148 options = {};
149 }
150
151 Hoek.assert(fn, `before in "${this._current.title}" requires a function argument`);
152
153 const before = {
154 title: 'Before ' + this._titles.join(' '),
155 fn,
156 options
157 };
158
159 this._current.befores = this._current.befores || [];
160 this._current.befores.push(before);
161};
162
163
164internals.after = function (options, fn) {
165
166 if (arguments.length !== 2) {
167 fn = options;
168 options = {};
169 }
170
171 Hoek.assert(fn, `after in "${this._current.title}" requires a function argument`);
172
173 const after = {
174 title: 'After ' + this._titles.join(' '),
175 fn,
176 options
177 };
178
179 this._current.afters = this._current.afters || [];
180 this._current.afters.push(after);
181};
182
183
184internals.beforeEach = function (options, fn) {
185
186 if (arguments.length !== 2) {
187 fn = options;
188 options = {};
189 }
190
191 Hoek.assert(fn, `beforeEach in "${this._current.title}" requires a function argument`);
192
193 const beforeEach = {
194 title: 'Before each ' + this._titles.join(' '),
195 fn,
196 options
197 };
198
199 this._current.beforeEaches = this._current.beforeEaches || [];
200 this._current.beforeEaches.push(beforeEach);
201};
202
203
204internals.afterEach = function (options, fn) {
205
206 if (arguments.length !== 2) {
207 fn = options;
208 options = {};
209 }
210
211 Hoek.assert(fn, `afterEach in "${this._current.title}" requires a function argument`);
212
213 const afterEach = {
214 title: 'After each ' + this._titles.join(' '),
215 fn,
216 options
217 };
218
219 this._current.afterEaches = this._current.afterEaches || [];
220 this._current.afterEaches.push(afterEach);
221};
222
223
224internals.test = function (title, options, fn) {
225
226 if (arguments.length !== 3) {
227 fn = options;
228 options = {};
229 }
230
231 const settings = Utils.mergeOptions(this._current.options, options, ['only']);
232
233 const test = {
234 path: this._path,
235 title: this._titles.concat(title).join(' '),
236 relativeTitle: title,
237 fn,
238 options: settings
239 };
240
241 if (settings.only) {
242 this.setOnly(this._current, test, this._path);
243 }
244
245 this._current.tests.push(test);
246};
247
248
249internals.skip = function (script, type) {
250
251 return function (title, options, fn) {
252
253 if (arguments.length !== 3) {
254 fn = options;
255 options = {};
256 }
257
258 script[type](title, Utils.mergeOptions({ skip: true }, options), fn);
259 };
260};
261
262
263internals.only = function (script, type) {
264
265 return function (title, options, fn) {
266
267 if (arguments.length !== 3) {
268 fn = options;
269 options = {};
270 }
271
272 script[type](title, Utils.mergeOptions({ only: true }, options), fn);
273 };
274};