UNPKG

3.76 kBJavaScriptView Raw
1'use strict';
2
3// Iron-node does not work with forked processes
4// This cli command will run a single file in the current process.
5// Intended to be used with iron-node for profiling purposes.
6
7const path = require('path');
8const EventEmitter = require('events');
9const meow = require('meow');
10const Promise = require('bluebird');
11const pkgConf = require('pkg-conf');
12const findCacheDir = require('find-cache-dir');
13const uniqueTempDir = require('unique-temp-dir');
14const arrify = require('arrify');
15const resolveCwd = require('resolve-cwd');
16const babelConfigHelper = require('./lib/babel-config');
17const CachingPrecompiler = require('./lib/caching-precompiler');
18const globals = require('./lib/globals');
19
20function resolveModules(modules) {
21 return arrify(modules).map(name => {
22 const modulePath = resolveCwd.silent(name);
23
24 if (modulePath === null) {
25 throw new Error(`Could not resolve required module '${name}'`);
26 }
27
28 return modulePath;
29 });
30}
31
32// Chrome gets upset when the `this` value is non-null for these functions
33globals.setTimeout = setTimeout.bind(null);
34globals.clearTimeout = clearTimeout.bind(null);
35
36Promise.longStackTraces();
37
38const conf = pkgConf.sync('ava', {
39 defaults: {
40 babel: 'default'
41 }
42});
43
44// Define a minimal set of options from the main CLI
45const cli = meow(`
46 Usage
47 $ iron-node node_modules/ava/profile.js <test-file>
48
49 Options
50 --fail-fast Stop after first test failure
51 --serial, -s Run tests serially
52
53`, {
54 string: [
55 '_'
56 ],
57 boolean: [
58 'fail-fast',
59 'verbose',
60 'serial',
61 'tap'
62 ],
63 default: conf,
64 alias: {
65 s: 'serial'
66 }
67});
68
69if (cli.input.length === 0) {
70 throw new Error('Specify a test file');
71}
72
73const file = path.resolve(cli.input[0]);
74const cacheDir = findCacheDir({
75 name: 'ava',
76 files: [file]
77}) || uniqueTempDir();
78
79babelConfigHelper.build(process.cwd(), cacheDir, conf.babel, true)
80 .then(result => {
81 const precompiler = new CachingPrecompiler({
82 path: cacheDir,
83 getBabelOptions: result.getOptions,
84 babelCacheKeys: result.cacheKeys
85 });
86
87 const precompiled = {};
88 precompiled[file] = precompiler.precompileFile(file);
89
90 const opts = {
91 file,
92 failFast: cli.flags.failFast,
93 serial: cli.flags.serial,
94 tty: false,
95 cacheDir,
96 precompiled,
97 require: resolveModules(conf.require)
98 };
99
100 const events = new EventEmitter();
101 let uncaughtExceptionCount = 0;
102
103 // Mock the behavior of a parent process
104 process.channel = {ref() {}, unref() {}};
105 process.send = data => {
106 if (data && data.ava) {
107 const name = data.name.replace(/^ava-/, '');
108
109 if (events.listeners(name).length > 0) {
110 events.emit(name, data.data);
111 } else {
112 console.log('UNHANDLED AVA EVENT:', name, data.data);
113 }
114
115 return;
116 }
117
118 console.log('NON AVA EVENT:', data);
119 };
120
121 events.on('test', data => {
122 console.log('TEST:', data.title, data.error);
123 });
124
125 events.on('results', data => {
126 if (console.profileEnd) {
127 console.profileEnd();
128 }
129
130 console.log('RESULTS:', data.stats);
131
132 if (process.exit) {
133 process.exit(data.stats.failCount + uncaughtExceptionCount); // eslint-disable-line unicorn/no-process-exit
134 }
135 });
136
137 events.on('stats', () => {
138 setImmediate(() => {
139 process.emit('ava-run', {});
140 });
141 });
142
143 events.on('uncaughtException', data => {
144 uncaughtExceptionCount++;
145 let stack = data && data.exception && data.exception.stack;
146 stack = stack || data;
147 console.log(stack);
148 });
149
150 // `test-worker` will read process.argv[2] for options
151 process.argv[2] = JSON.stringify(opts);
152 process.argv.length = 3;
153
154 if (console.profile) {
155 console.profile('AVA test-worker process');
156 }
157
158 setImmediate(() => {
159 require('./lib/test-worker'); // eslint-disable-line import/no-unassigned-import
160 });
161 });