UNPKG

10.5 kBJavaScriptView Raw
1'use strict'
2
3const path = require('path')
4const yargs = require('yargs')
5const fs = require('graceful-fs')
6
7const Server = require('./server')
8const helper = require('./helper')
9const constant = require('./constants')
10
11function processArgs (argv, options, fs, path) {
12 Object.getOwnPropertyNames(argv).forEach(function (name) {
13 let argumentValue = argv[name]
14 if (name !== '_' && name !== '$0') {
15 if (Array.isArray(argumentValue)) {
16 argumentValue = argumentValue.pop() // If the same argument is defined multiple times, override.
17 }
18 options[helper.dashToCamel(name)] = argumentValue
19 }
20 })
21
22 if (helper.isString(options.autoWatch)) {
23 options.autoWatch = options.autoWatch === 'true'
24 }
25
26 if (helper.isString(options.colors)) {
27 options.colors = options.colors === 'true'
28 }
29
30 if (helper.isString(options.failOnEmptyTestSuite)) {
31 options.failOnEmptyTestSuite = options.failOnEmptyTestSuite === 'true'
32 }
33
34 if (helper.isString(options.failOnFailingTestSuite)) {
35 options.failOnFailingTestSuite = options.failOnFailingTestSuite === 'true'
36 }
37
38 if (helper.isString(options.formatError)) {
39 let required
40 try {
41 required = require(options.formatError)
42 } catch (err) {
43 console.error('Could not require formatError: ' + options.formatError, err)
44 }
45 // support exports.formatError and module.exports = function
46 options.formatError = required.formatError || required
47 if (!helper.isFunction(options.formatError)) {
48 console.error(`Format error must be a function, got: ${typeof options.formatError}`)
49 process.exit(1)
50 }
51 }
52
53 if (helper.isString(options.logLevel)) {
54 const logConstant = constant['LOG_' + options.logLevel.toUpperCase()]
55 if (helper.isDefined(logConstant)) {
56 options.logLevel = logConstant
57 } else {
58 console.error('Log level must be one of disable, error, warn, info, or debug.')
59 process.exit(1)
60 }
61 } else if (helper.isDefined(options.logLevel)) {
62 console.error('Log level must be one of disable, error, warn, info, or debug.')
63 process.exit(1)
64 }
65
66 if (helper.isString(options.singleRun)) {
67 options.singleRun = options.singleRun === 'true'
68 }
69
70 if (helper.isString(options.browsers)) {
71 options.browsers = options.browsers.split(',')
72 }
73
74 if (options.reportSlowerThan === false) {
75 options.reportSlowerThan = 0
76 }
77
78 if (helper.isString(options.reporters)) {
79 options.reporters = options.reporters.split(',')
80 }
81
82 if (helper.isString(options.removedFiles)) {
83 options.removedFiles = options.removedFiles.split(',')
84 }
85
86 if (helper.isString(options.addedFiles)) {
87 options.addedFiles = options.addedFiles.split(',')
88 }
89
90 if (helper.isString(options.changedFiles)) {
91 options.changedFiles = options.changedFiles.split(',')
92 }
93
94 if (helper.isString(options.refresh)) {
95 options.refresh = options.refresh === 'true'
96 }
97
98 let configFile = argv.configFile
99
100 if (!configFile) {
101 // default config file (if exists)
102 if (fs.existsSync('./karma.conf.js')) {
103 configFile = './karma.conf.js'
104 } else if (fs.existsSync('./karma.conf.coffee')) {
105 configFile = './karma.conf.coffee'
106 } else if (fs.existsSync('./karma.conf.ts')) {
107 configFile = './karma.conf.ts'
108 } else if (fs.existsSync('./.config/karma.conf.js')) {
109 configFile = './.config/karma.conf.js'
110 } else if (fs.existsSync('./.config/karma.conf.coffee')) {
111 configFile = './.config/karma.conf.coffee'
112 } else if (fs.existsSync('./.config/karma.conf.ts')) {
113 configFile = './.config/karma.conf.ts'
114 }
115 }
116
117 options.configFile = configFile ? path.resolve(configFile) : null
118
119 if (options.cmd === 'run') {
120 options.clientArgs = parseClientArgs(process.argv)
121 }
122
123 return options
124}
125
126function parseClientArgs (argv) {
127 // extract any args after '--' as clientArgs
128 let clientArgs = []
129 argv = argv.slice(2)
130 const idx = argv.indexOf('--')
131 if (idx !== -1) {
132 clientArgs = argv.slice(idx + 1)
133 }
134 return clientArgs
135}
136
137// return only args that occur before `--`
138function argsBeforeDoubleDash (argv) {
139 const idx = argv.indexOf('--')
140
141 return idx === -1 ? argv : argv.slice(0, idx)
142}
143
144function describeRoot () {
145 return yargs
146 .usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
147 'Run --help with particular command to see its description and available options.\n\n' +
148 'Usage:\n' +
149 ' $0 <command>')
150 .command('init [configFile]', 'Initialize a config file.', describeInit)
151 .command('start [configFile]', 'Start the server / do a single run.', describeStart)
152 .command('run [configFile]', 'Trigger a test run.', describeRun)
153 .command('stop [configFile]', 'Stop the server.', describeStop)
154 .command('completion', 'Shell completion for karma.', describeCompletion)
155 .demandCommand(1, 'Command not specified.')
156 .strict()
157 .describe('help', 'Print usage and options.')
158 .describe('version', 'Print current version.')
159}
160
161function describeInit (yargs) {
162 yargs
163 .usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
164 'INIT - Initialize a config file.\n\n' +
165 'Usage:\n' +
166 ' $0 init [configFile]')
167 .version(false)
168 .positional('configFile', {
169 describe: 'Name of the generated Karma configuration file',
170 type: 'string'
171 })
172 .describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
173 .describe('colors', 'Use colors when reporting and printing logs.')
174 .describe('no-colors', 'Do not use colors when reporting or printing logs.')
175}
176
177function describeStart (yargs) {
178 yargs
179 .usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
180 'START - Start the server / do a single run.\n\n' +
181 'Usage:\n' +
182 ' $0 start [configFile]')
183 .strictCommands(false)
184 .version(false)
185 .positional('configFile', {
186 describe: 'Path to the Karma configuration file',
187 type: 'string'
188 })
189 .describe('port', '<integer> Port where the server is running.')
190 .describe('auto-watch', 'Auto watch source files and run on change.')
191 .describe('detached', 'Detach the server.')
192 .describe('no-auto-watch', 'Do not watch source files.')
193 .describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
194 .describe('colors', 'Use colors when reporting and printing logs.')
195 .describe('no-colors', 'Do not use colors when reporting or printing logs.')
196 .describe('reporters', 'List of reporters (available: dots, progress, junit, growl, coverage).')
197 .describe('browsers', 'List of browsers to start (eg. --browsers Chrome,ChromeCanary,Firefox).')
198 .describe('capture-timeout', '<integer> Kill browser if does not capture in given time [ms].')
199 .describe('single-run', 'Run the test when browsers captured and exit.')
200 .describe('no-single-run', 'Disable single-run.')
201 .describe('report-slower-than', '<integer> Report tests that are slower than given time [ms].')
202 .describe('fail-on-empty-test-suite', 'Fail on empty test suite.')
203 .describe('no-fail-on-empty-test-suite', 'Do not fail on empty test suite.')
204 .describe('fail-on-failing-test-suite', 'Fail on failing test suite.')
205 .describe('no-fail-on-failing-test-suite', 'Do not fail on failing test suite.')
206 .option('format-error', {
207 describe: 'A path to a file that exports the format function.',
208 type: 'string'
209 })
210}
211
212function describeRun (yargs) {
213 yargs
214 .usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
215 'RUN - Run the tests (requires running server).\n\n' +
216 'Usage:\n' +
217 ' $0 run [configFile] [-- <clientArgs>]')
218 .version(false)
219 .positional('configFile', {
220 describe: 'Path to the Karma configuration file',
221 type: 'string'
222 })
223 .describe('port', '<integer> Port where the server is listening.')
224 .describe('no-refresh', 'Do not re-glob all the patterns.')
225 .describe('fail-on-empty-test-suite', 'Fail on empty test suite.')
226 .describe('no-fail-on-empty-test-suite', 'Do not fail on empty test suite.')
227 .describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
228 .describe('colors', 'Use colors when reporting and printing logs.')
229 .describe('no-colors', 'Do not use colors when reporting or printing logs.')
230 .option('removed-files', {
231 describe: 'Comma-separated paths to removed files. Useful when automatic file watching is disabled.',
232 type: 'string'
233 })
234 .option('changed-files', {
235 describe: 'Comma-separated paths to changed files. Useful when automatic file watching is disabled.',
236 type: 'string'
237 })
238 .option('added-files', {
239 describe: 'Comma-separated paths to added files. Useful when automatic file watching is disabled.',
240 type: 'string'
241 })
242}
243
244function describeStop (yargs) {
245 yargs
246 .usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
247 'STOP - Stop the server (requires running server).\n\n' +
248 'Usage:\n' +
249 ' $0 stop [configFile]')
250 .version(false)
251 .positional('configFile', {
252 describe: 'Path to the Karma configuration file',
253 type: 'string'
254 })
255 .describe('port', '<integer> Port where the server is listening.')
256 .describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
257}
258
259function describeCompletion (yargs) {
260 yargs
261 .usage('Karma - Spectacular Test Runner for JavaScript.\n\n' +
262 'COMPLETION - Bash/ZSH completion for karma.\n\n' +
263 'Installation:\n' +
264 ' $0 completion >> ~/.bashrc')
265 .version(false)
266}
267
268function printRunnerProgress (data) {
269 process.stdout.write(data)
270}
271
272exports.process = () => {
273 const argv = describeRoot().parse(argsBeforeDoubleDash(process.argv.slice(2)))
274 return processArgs(argv, { cmd: argv._.shift() }, fs, path)
275}
276
277exports.run = () => {
278 const config = exports.process()
279
280 switch (config.cmd) {
281 case 'start':
282 new Server(config).start()
283 break
284 case 'run':
285 require('./runner')
286 .run(config)
287 .on('progress', printRunnerProgress)
288 break
289 case 'stop':
290 require('./stopper').stop(config)
291 break
292 case 'init':
293 require('./init').init(config)
294 break
295 case 'completion':
296 require('./completion').completion(config)
297 break
298 }
299}
300
301// just for testing
302exports.processArgs = processArgs
303exports.parseClientArgs = parseClientArgs
304exports.argsBeforeDoubleDash = argsBeforeDoubleDash