UNPKG

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