]>
Commit | Line | Data |
---|---|---|
2af86592 SR |
1 | #!/usr/bin/env node |
2 | var ansi = require('ansi'); | |
3 | var program = require('commander'); | |
4 | var path = require('path'); | |
d823e895 | 5 | var fs = require('fs'); |
2af86592 SR |
6 | |
7 | var make_list = function(val) { | |
8 | return val.split(','); | |
8eb88937 | 9 | }; |
2af86592 SR |
10 | |
11 | program | |
12 | .option('-t, --tests <testlist>', 'Run the specified html-file-based test(s). \'testlist\' should be a comma-separated list', make_list, []) | |
13 | .option('-a, --print-all', 'Print all tests, not just the failures') | |
14 | .option('--disable-color', 'Explicitly disable color') | |
15 | .option('-c, --color', 'Explicitly enable color (default is to use color when not outputting to a pipe)') | |
16 | .option('-i, --auto-inject <includefiles>', 'Treat the test list as a set of mocha JS files, and automatically generate HTML files with which to test test. \'includefiles\' should be a comma-separated list of paths to javascript files to include in each of the generated HTML files', make_list, null) | |
17 | .option('-p, --provider <name>', 'Use the given provider (defaults to "casper"). Currently, may be "casper" or "zombie"', 'casper') | |
4a4643c0 SR |
18 | .option('-g, --generate-html', 'Instead of running the tests, just return the path to the generated HTML file, then wait for user interaction to exit (should be used with .js tests).') |
19 | .option('-o, --open-in-browser', 'Open the generated HTML files in a web browser using the "open" module (must be used with the "-g"/"--generate-html" option).') | |
85e89916 | 20 | .option('-o, --output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with .js tests)') |
8eb88937 | 21 | .option('-d, --debug', 'Show debug output (the "console" event) from the provider') |
2af86592 SR |
22 | .parse(process.argv); |
23 | ||
d823e895 SR |
24 | if (program.tests.length === 0) { |
25 | program.tests = fs.readdirSync(__dirname).filter(function(f) { return (/^test\.(\w|\.|-)+\.js$/).test(f); }); | |
91127741 | 26 | program.tests = program.tests.map(function (f) { return path.resolve(__dirname, f); }); // add full paths in |
d823e895 SR |
27 | console.log('using files %s', program.tests); |
28 | } | |
29 | ||
2af86592 SR |
30 | var file_paths = []; |
31 | ||
85e89916 SR |
32 | var all_js = program.tests.reduce(function(a,e) { return a && e.slice(-3) == '.js'; }, true); |
33 | ||
34 | if (all_js && !program.autoInject) { | |
35 | var all_modules = {}; | |
36 | ||
37 | // uses the first instance of the string 'requires local modules: ' | |
38 | program.tests.forEach(function (testname) { | |
39 | var full_path = path.resolve(process.cwd(), testname); | |
40 | var content = fs.readFileSync(full_path).toString(); | |
41 | var ind = content.indexOf('requires local modules: '); | |
42 | if (ind > -1) { | |
43 | ind += 'requires local modules: '.length; | |
44 | var eol = content.indexOf('\n', ind); | |
45 | var modules = content.slice(ind, eol).split(/,\s*/); | |
46 | modules.forEach(function (mod) { | |
47 | all_modules[path.resolve(__dirname, '../include/', mod)+'.js'] = 1; | |
48 | }); | |
49 | } | |
d906dfc9 | 50 | |
7187bc12 | 51 | var fakes_ind = content.indexOf('requires test modules: '); |
d906dfc9 SR |
52 | if (fakes_ind > -1) { |
53 | fakes_ind += 'requires test modules: '.length; | |
54 | var fakes_eol = content.indexOf('\n', fakes_ind); | |
55 | var fakes_modules = content.slice(fakes_ind, fakes_eol).split(/,\s*/); | |
56 | fakes_modules.forEach(function (mod) { | |
57 | all_modules[path.resolve(__dirname, mod) + '.js'] = 1; | |
58 | }); | |
59 | } | |
85e89916 SR |
60 | }); |
61 | ||
62 | program.autoInject = Object.keys(all_modules); | |
63 | } | |
64 | ||
2af86592 SR |
65 | if (program.autoInject) { |
66 | var temp = require('temp'); | |
2af86592 SR |
67 | temp.track(); |
68 | ||
69 | var template = { | |
e6af0f60 | 70 | header: "<html>\n<head>\n<meta charset='utf-8' />\n<link rel='stylesheet' href='" + path.resolve(__dirname, '../node_modules/mocha/mocha.css') + "'/>\n</head>\n<body><div id='mocha'></div>", |
8eb88937 | 71 | script_tag: function(p) { return "<script src='" + p + "'></script>"; }, |
9b731d3a | 72 | footer: "<script>\nmocha.checkLeaks();\nmocha.globals(['navigator', 'create', 'ClientUtils', '__utils__']);\nmocha.run(function () { window.__mocha_done = true; });\n</script>\n</body>\n</html>" |
2af86592 SR |
73 | }; |
74 | ||
e6af0f60 SR |
75 | template.header += "\n" + template.script_tag(path.resolve(__dirname, '../node_modules/chai/chai.js')); |
76 | template.header += "\n" + template.script_tag(path.resolve(__dirname, '../node_modules/mocha/mocha.js')); | |
77 | template.header += "\n" + template.script_tag(path.resolve(__dirname, '../node_modules/sinon/pkg/sinon.js')); | |
78 | template.header += "\n" + template.script_tag(path.resolve(__dirname, '../node_modules/sinon-chai/lib/sinon-chai.js')); | |
79 | template.header += "\n" + template.script_tag(path.resolve(__dirname, '../node_modules/sinon-chai/lib/sinon-chai.js')); | |
2af86592 SR |
80 | template.header += "\n<script>mocha.setup('bdd');</script>"; |
81 | ||
82 | ||
83 | template.header = program.autoInject.reduce(function(acc, sn) { | |
84 | return acc + "\n" + template.script_tag(path.resolve(process.cwd(), sn)); | |
85 | }, template.header); | |
86 | ||
87 | file_paths = program.tests.map(function(jsn, ind) { | |
88 | var templ = template.header; | |
89 | templ += "\n"; | |
90 | templ += template.script_tag(path.resolve(process.cwd(), jsn)); | |
91 | templ += template.footer; | |
92 | ||
93 | var tempfile = temp.openSync({ prefix: 'novnc-zombie-inject-', suffix: '-file_num-'+ind+'.html' }); | |
94 | fs.writeSync(tempfile.fd, templ); | |
95 | fs.closeSync(tempfile.fd); | |
96 | return tempfile.path; | |
97 | }); | |
98 | ||
99 | } | |
100 | else { | |
101 | file_paths = program.tests.map(function(fn) { | |
102 | return path.resolve(process.cwd(), fn); | |
103 | }); | |
104 | } | |
105 | ||
2af86592 SR |
106 | var use_ansi = false; |
107 | if (program.color) use_ansi = true; | |
108 | else if (program.disableColor) use_ansi = false; | |
109 | else if (process.stdout.isTTY) use_ansi = true; | |
110 | ||
111 | var cursor = ansi(process.stdout, { enabled: use_ansi }); | |
112 | ||
1e570156 | 113 | if (program.outputHtml) { |
1e570156 SR |
114 | file_paths.forEach(function(path, path_ind) { |
115 | fs.readFile(path, function(err, data) { | |
116 | if (err) { | |
117 | console.warn(error.stack); | |
118 | return; | |
119 | } | |
8eb88937 | 120 | |
1e570156 SR |
121 | cursor |
122 | .bold() | |
123 | .write(program.tests[path_ind]) | |
124 | .reset() | |
125 | .write("\n") | |
126 | .write(Array(program.tests[path_ind].length+1).join('=')) | |
127 | .write("\n\n") | |
128 | .write(data) | |
129 | .write("\n"); | |
130 | }); | |
131 | }); | |
132 | } | |
133 | ||
134 | if (program.generateHtml) { | |
4a4643c0 SR |
135 | var open_browser; |
136 | if (program.openInBrowser) { | |
137 | open_browser = require('open'); | |
138 | } | |
139 | ||
1e570156 SR |
140 | file_paths.forEach(function(path, path_ind) { |
141 | cursor | |
142 | .bold() | |
143 | .write(program.tests[path_ind]) | |
144 | .write(": ") | |
145 | .reset() | |
146 | .write(path) | |
147 | .write("\n"); | |
4a4643c0 SR |
148 | |
149 | if (program.openInBrowser) { | |
150 | open_browser(path); | |
151 | } | |
1e570156 | 152 | }); |
2af86592 | 153 | console.log(''); |
1e570156 | 154 | } |
2af86592 | 155 | |
1e570156 SR |
156 | if (program.generateHtml) { |
157 | process.stdin.resume(); // pause until C-c | |
158 | process.on('SIGINT', function() { | |
159 | process.stdin.pause(); // exit | |
160 | }); | |
161 | } | |
2af86592 | 162 | |
1e570156 SR |
163 | if (!program.outputHtml && !program.generateHtml) { |
164 | var failure_count = 0; | |
2af86592 | 165 | |
1e570156 | 166 | var prov = require(path.resolve(__dirname, 'run_from_console.'+program.provider+'.js')); |
2af86592 | 167 | |
2af86592 | 168 | cursor |
1e570156 SR |
169 | .write("Running tests ") |
170 | .bold() | |
171 | .write(program.tests.join(', ')) | |
2af86592 | 172 | .reset() |
1e570156 SR |
173 | .grey() |
174 | .write(' using provider '+prov.name) | |
2af86592 | 175 | .reset() |
1e570156 SR |
176 | .write("\n"); |
177 | //console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name); | |
2af86592 | 178 | |
1e570156 SR |
179 | var provider = prov.provide_emitter(file_paths); |
180 | provider.on('test_ready', function(test_json) { | |
181 | console.log(''); | |
2af86592 | 182 | |
1e570156 | 183 | filename = program.tests[test_json.file_ind]; |
2af86592 | 184 | |
1e570156 SR |
185 | cursor.bold(); |
186 | console.log('Results for %s:', filename); | |
187 | console.log(Array('Results for :'.length+filename.length+1).join('=')); | |
188 | cursor.reset(); | |
2af86592 | 189 | |
1e570156 SR |
190 | console.log(''); |
191 | ||
1e570156 | 192 | cursor |
8eb88937 | 193 | .write(''+test_json.num_tests+' tests run, ') |
1e570156 SR |
194 | .green() |
195 | .write(''+test_json.num_passes+' passed'); | |
196 | if (test_json.num_slow > 0) { | |
197 | cursor | |
198 | .reset() | |
199 | .write(' ('); | |
200 | cursor | |
201 | .yellow() | |
202 | .write(''+test_json.num_slow+' slow') | |
203 | .reset() | |
204 | .write(')'); | |
205 | } | |
206 | cursor | |
207 | .reset() | |
208 | .write(', '); | |
209 | cursor | |
210 | .red() | |
211 | .write(''+test_json.num_fails+' failed'); | |
8eb88937 SR |
212 | if (test_json.num_skipped > 0) { |
213 | cursor | |
214 | .reset() | |
215 | .write(', ') | |
216 | .grey() | |
217 | .write(''+test_json.num_skipped+' skipped'); | |
218 | } | |
1e570156 SR |
219 | cursor |
220 | .reset() | |
8eb88937 | 221 | .write(' -- duration: '+test_json.duration+"s\n"); |
1e570156 SR |
222 | |
223 | console.log(''); | |
224 | ||
225 | if (test_json.num_fails > 0 || program.printAll) { | |
226 | var traverse_tree = function(indentation, node) { | |
227 | if (node.type == 'suite') { | |
228 | if (!node.has_subfailures && !program.printAll) return; | |
229 | ||
8eb88937 | 230 | if (indentation === 0) { |
1e570156 SR |
231 | cursor.bold(); |
232 | console.log(node.name); | |
233 | console.log(Array(node.name.length+1).join('-')); | |
234 | cursor.reset(); | |
235 | } | |
236 | else { | |
237 | cursor | |
238 | .write(Array(indentation+3).join('#')) | |
239 | .bold() | |
240 | .write(' '+node.name+' ') | |
241 | .reset() | |
242 | .write(Array(indentation+3).join('#')) | |
243 | .write("\n"); | |
244 | } | |
2af86592 | 245 | |
2af86592 | 246 | console.log(''); |
1e570156 SR |
247 | |
248 | for (var i = 0; i < node.children.length; i++) { | |
249 | traverse_tree(indentation+1, node.children[i]); | |
250 | } | |
2af86592 | 251 | } |
1e570156 SR |
252 | else { |
253 | if (!node.pass) { | |
254 | cursor.magenta(); | |
255 | console.log('- failed: '+node.text+test_json.replay); | |
256 | cursor.red(); | |
8eb88937 | 257 | console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS where we get a stack trace too |
1e570156 SR |
258 | cursor.reset(); |
259 | console.log(''); | |
260 | } | |
261 | else if (program.printAll) { | |
8eb88937 SR |
262 | if (node.skipped) { |
263 | cursor | |
264 | .grey() | |
265 | .write('- skipped: '+node.text); | |
266 | } | |
267 | else { | |
268 | if (node.slow) cursor.yellow(); | |
269 | else cursor.green(); | |
270 | ||
271 | cursor | |
272 | .write('- pass: '+node.text) | |
273 | .grey() | |
274 | .write(' ('+node.duration+') '); | |
275 | } | |
1e570156 SR |
276 | /*if (node.slow) cursor.yellow(); |
277 | else cursor.green();*/ | |
278 | cursor | |
279 | //.write(test_json.replay) | |
280 | .reset() | |
281 | .write("\n"); | |
282 | console.log(''); | |
283 | } | |
2af86592 | 284 | } |
8eb88937 | 285 | }; |
2af86592 | 286 | |
1e570156 SR |
287 | for (var i = 0; i < test_json.suites.length; i++) { |
288 | traverse_tree(0, test_json.suites[i]); | |
289 | } | |
2af86592 | 290 | } |
2af86592 | 291 | |
8eb88937 | 292 | if (test_json.num_fails === 0) { |
1e570156 SR |
293 | cursor.fg.green(); |
294 | console.log('all tests passed :-)'); | |
295 | cursor.reset(); | |
296 | } | |
297 | }); | |
2af86592 | 298 | |
8eb88937 SR |
299 | if (program.debug) { |
300 | provider.on('console', function(line) { | |
93af721a SR |
301 | // log to stderr |
302 | console.error(line); | |
8eb88937 SR |
303 | }); |
304 | } | |
2af86592 | 305 | |
93af721a SR |
306 | provider.on('error', function(line) { |
307 | // log to stderr | |
308 | console.error('ERROR: ' + line); | |
309 | }); | |
310 | ||
1e570156 SR |
311 | /*gprom.finally(function(ph) { |
312 | ph.exit(); | |
313 | // exit with a status code that actually gives information | |
314 | if (program.exitWithFailureCount) process.exit(failure_count); | |
315 | });*/ | |
316 | } |