UNPKG

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