UNPKG

9.56 kBJavaScriptView Raw
1"use strict";
2/**
3 * @module SlimRunner
4 */
5var __importDefault = (this && this.__importDefault) || function (mod) {
6 return (mod && mod.__esModule) ? mod : { "default": mod };
7};
8Object.defineProperty(exports, "__esModule", { value: true });
9exports.run = exports.test = void 0;
10/*
11 * japa
12 *
13 * (c) Harminder Virk <virk@adonisjs.com>
14 *
15 * For the full copyright and license information, please view the LICENSE
16 * file that was distributed with this source code.
17*/
18const chalk_1 = __importDefault(require("chalk"));
19const Group_1 = require("../Group");
20const Loader_1 = require("./Loader");
21const Runner_1 = require("../Runner");
22const Assert_1 = require("../Assert");
23const Emitter_1 = require("../Emitter");
24const list_1 = __importDefault(require("../Reporter/list"));
25const loader = new Loader_1.Loader();
26/**
27 * Returns arguments to be passed to the callback
28 * of a test
29 */
30function testArgsFn(done, postRun) {
31 postRun(function postRunFn(assert) {
32 assert.evaluate();
33 });
34 return [new Assert_1.Assert(), done];
35}
36/**
37 * Returns arguments to be passed to the callback of
38 * a hook
39 */
40function hookArgsFn(done) {
41 return [done];
42}
43/**
44 * Store of groups
45 */
46let groups = [];
47/**
48 * The active group, in which all tests must be scoped
49 */
50let activeGroup = null;
51/**
52 * A flag to track, if `test.only` is used to cherry pick a
53 * single test. All other tests are ignored from here
54 * on.
55 */
56let cherryPickedTest = false;
57/**
58 * Import files instead of require. This does not enable
59 */
60let experimentalEsmSupport = false;
61/**
62 * Options for the test runner
63 */
64let runnerOptions = {
65 bail: false,
66 timeout: 2000,
67};
68/**
69 * Custom reporter function
70 */
71let reporterFn = list_1.default;
72/**
73 * Reference to runner hooks, to be defined inside configure
74 * method
75 */
76let beforeHooks = [];
77let afterHooks = [];
78/**
79 * Adds the test to the active group. If there isn't any active
80 * group, it will be created.
81 */
82function addTest(title, callback, options) {
83 if (!activeGroup) {
84 activeGroup = new Group_1.Group('root', testArgsFn, hookArgsFn, runnerOptions);
85 groups.push(activeGroup);
86 }
87 return activeGroup.test(title, callback, options);
88}
89/**
90 * Create a new test
91 */
92function test(title, callback) {
93 return addTest(title, callback);
94}
95exports.test = test;
96/**
97 * Run all the tests using the runner
98 */
99async function run(exitProcess = true) {
100 const runner = new Runner_1.Runner([], runnerOptions);
101 runner.reporter(reporterFn);
102 /**
103 * Execute before hooks before loading any files
104 * from the disk
105 */
106 for (let hook of beforeHooks) {
107 await hook(runner, Emitter_1.emitter);
108 }
109 const loaderFiles = await loader.loadFiles();
110 if (loaderFiles.length && groups.length) {
111 console.log(chalk_1.default.bgRed('Calling configure inside test file is not allowed. Create a master file for same'));
112 process.exit(1);
113 }
114 /**
115 * Load all files from the loader
116 */
117 await Promise.all(loaderFiles.map((file) => {
118 /**
119 * Do not require more files, when cherry picking
120 * tests
121 */
122 if (cherryPickedTest) {
123 return;
124 }
125 /**
126 * Explicit ESM
127 */
128 if (file.endsWith('.mjs')) {
129 return import(file);
130 }
131 /**
132 * Explicit CommonJS
133 */
134 if (file.endsWith('.cjs')) {
135 return require(file);
136 }
137 /**
138 * Opt in ESM
139 */
140 if (experimentalEsmSupport) {
141 return import(file);
142 }
143 /**
144 * Defaults to CommonJS
145 */
146 return require(file);
147 }));
148 let hardException = null;
149 try {
150 await runner.useGroups(groups).run();
151 }
152 catch (error) {
153 hardException = error;
154 }
155 /**
156 * Executing after hooks before cleanup
157 */
158 for (let hook of afterHooks) {
159 await hook(runner, Emitter_1.emitter);
160 }
161 if (exitProcess) {
162 runner.hasErrors || hardException ? process.exit(1) : process.exit(0);
163 }
164 groups = [];
165 activeGroup = null;
166}
167exports.run = run;
168// eslint-disable-next-line no-redeclare
169(function (test) {
170 /**
171 * Create a new test to group all test together
172 */
173 function group(title, callback) {
174 /**
175 * Do not add new groups when already cherry picked a test
176 */
177 if (cherryPickedTest) {
178 return;
179 }
180 activeGroup = new Group_1.Group(title, testArgsFn, hookArgsFn, runnerOptions);
181 /**
182 * Track the group
183 */
184 groups.push(activeGroup);
185 /**
186 * Pass instance of the group to the callback. This enables defining lifecycle
187 * hooks
188 */
189 callback(activeGroup);
190 /**
191 * Reset group after callback has been executed
192 */
193 activeGroup = null;
194 }
195 test.group = group;
196 /**
197 * Only run the specified test
198 */
199 function only(title, callback) {
200 const testInstance = addTest(title, callback, { only: true });
201 /**
202 * Empty out existing groups
203 */
204 groups = [];
205 /**
206 * Push the current active group
207 */
208 groups.push(activeGroup);
209 /**
210 * Turn on the flag
211 */
212 cherryPickedTest = true;
213 return testInstance;
214 }
215 test.only = only;
216 /**
217 * Create a test, and mark it as skipped. Skipped functions are
218 * never executed. However, their hooks are executed
219 */
220 function skip(title, callback) {
221 return addTest(title, callback, { skip: true });
222 }
223 test.skip = skip;
224 /**
225 * Create a test, and mark it as skipped only when running in CI. Skipped
226 * functions are never executed. However, their hooks are executed.
227 */
228 function skipInCI(title, callback) {
229 return addTest(title, callback, { skipInCI: true });
230 }
231 test.skipInCI = skipInCI;
232 /**
233 * Create a test and run it only in the CI.
234 */
235 function runInCI(title, callback) {
236 return addTest(title, callback, { runInCI: true });
237 }
238 test.runInCI = runInCI;
239 /**
240 * Create regression test
241 */
242 function failing(title, callback) {
243 return addTest(title, callback, { regression: true });
244 }
245 test.failing = failing;
246 /**
247 * Configure test runner
248 */
249 function configure(options) {
250 /**
251 * Reset runner options before every configure call
252 */
253 runnerOptions = {
254 bail: false,
255 timeout: 2000,
256 };
257 if (groups.length) {
258 throw new Error('test.configure must be called before creating any tests');
259 }
260 /**
261 * Hold repoter fn to be passed to the runner
262 */
263 if (options.reporterFn) {
264 reporterFn = options.reporterFn;
265 }
266 /**
267 * Use bail option if defined by the end user
268 */
269 if (options.bail !== undefined) {
270 runnerOptions.bail = options.bail;
271 }
272 /**
273 * Use timeout if defined by the end user
274 */
275 if (typeof (options.timeout) === 'number') {
276 runnerOptions.timeout = options.timeout;
277 }
278 /**
279 * Use files glob if defined
280 */
281 if (options.files !== undefined) {
282 loader.files(options.files);
283 }
284 /**
285 * Use files filter if defined as function
286 */
287 if (typeof (options.filter) === 'function') {
288 loader.filter(options.filter);
289 }
290 /**
291 * Set after hooks
292 */
293 if (options.before) {
294 if (!Array.isArray(options.before)) {
295 throw new Error('"configure.before" expects an array of functions');
296 }
297 options.before.forEach((fn, index) => {
298 if (typeof (fn) !== 'function') {
299 throw new Error(`invalid value for "configure.before" at ${index} index`);
300 }
301 });
302 beforeHooks = options.before;
303 }
304 /**
305 * Set before hooks
306 */
307 if (options.after) {
308 if (!Array.isArray(options.after)) {
309 throw new Error('"configure.after" expects an array of functions');
310 }
311 options.after.forEach((fn, index) => {
312 if (typeof (fn) !== 'function') {
313 throw new Error(`invalid value for "configure.after" at ${index} index`);
314 }
315 });
316 afterHooks = options.after;
317 }
318 /**
319 * If grep is defined, then normalize it to regex
320 */
321 if (options.grep) {
322 runnerOptions.grep = options.grep instanceof RegExp ? options.grep : new RegExp(options.grep);
323 }
324 /**
325 * The test files are written in ESM
326 */
327 if (options.experimentalEsmSupport) {
328 experimentalEsmSupport = true;
329 }
330 }
331 test.configure = configure;
332 /**
333 * Nested only
334 */
335 (function (failing) {
336 /**
337 * Only run the specified test
338 */
339 // eslint-disable-next-line @typescript-eslint/no-shadow
340 function only(title, callback) {
341 runnerOptions.grep = new RegExp(title);
342 return addTest(title, callback, { regression: true });
343 }
344 failing.only = only;
345 })(failing = test.failing || (test.failing = {}));
346})(test = exports.test || (exports.test = {}));