UNPKG

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