]> git.proxmox.com Git - mirror_novnc.git/blame - tests/run_from_console.js
Enable noVNC to become Browserifiable
[mirror_novnc.git] / tests / run_from_console.js
CommitLineData
2af86592
SR
1#!/usr/bin/env node
2var ansi = require('ansi');
3var program = require('commander');
4var path = require('path');
d823e895 5var fs = require('fs');
2af86592
SR
6
7var make_list = function(val) {
8 return val.split(',');
8eb88937 9};
2af86592
SR
10
11program
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).')
b11bb5c3 20 .option('--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')
b11bb5c3 22 .option('-r, --relative', 'Use relative paths in the generated HTML file')
07f514d8 23 .option('--debugger <port>', 'Enable the remote debugger for CasperJS')
2af86592
SR
24 .parse(process.argv);
25
d823e895
SR
26if (program.tests.length === 0) {
27 program.tests = fs.readdirSync(__dirname).filter(function(f) { return (/^test\.(\w|\.|-)+\.js$/).test(f); });
91127741 28 program.tests = program.tests.map(function (f) { return path.resolve(__dirname, f); }); // add full paths in
d823e895
SR
29 console.log('using files %s', program.tests);
30}
31
2af86592
SR
32var file_paths = [];
33
85e89916
SR
34var all_js = program.tests.reduce(function(a,e) { return a && e.slice(-3) == '.js'; }, true);
35
b11bb5c3
SR
36var get_path = function (/* arguments */) {
37 if (program.relative) {
38 return path.join.apply(null, arguments);
39 } else {
40 var args = Array.prototype.slice.call(arguments);
41 args.unshift(__dirname, '..');
42 return path.resolve.apply(null, args);
43 }
44};
45
46var get_path_cwd = function (/* arguments */) {
47 if (program.relative) {
48 var part_path = path.join.apply(null, arguments);
49 return path.relative(path.join(__dirname, '..'), path.resolve(process.cwd(), part_path));
50 } else {
51 var args = Array.prototype.slice.call(arguments);
52 args.unshift(process.cwd());
53 return path.resolve.apply(null, args);
54 }
55};
56
85e89916
SR
57if (all_js && !program.autoInject) {
58 var all_modules = {};
59
60 // uses the first instance of the string 'requires local modules: '
61 program.tests.forEach(function (testname) {
62 var full_path = path.resolve(process.cwd(), testname);
63 var content = fs.readFileSync(full_path).toString();
64 var ind = content.indexOf('requires local modules: ');
65 if (ind > -1) {
66 ind += 'requires local modules: '.length;
67 var eol = content.indexOf('\n', ind);
68 var modules = content.slice(ind, eol).split(/,\s*/);
69 modules.forEach(function (mod) {
ae510306 70 all_modules[get_path('core/', mod) + '.js'] = 1;
85e89916
SR
71 });
72 }
d906dfc9 73
7187bc12 74 var fakes_ind = content.indexOf('requires test modules: ');
d906dfc9
SR
75 if (fakes_ind > -1) {
76 fakes_ind += 'requires test modules: '.length;
77 var fakes_eol = content.indexOf('\n', fakes_ind);
78 var fakes_modules = content.slice(fakes_ind, fakes_eol).split(/,\s*/);
79 fakes_modules.forEach(function (mod) {
b11bb5c3 80 all_modules[get_path('tests/', mod) + '.js'] = 1;
d906dfc9
SR
81 });
82 }
85e89916
SR
83 });
84
85 program.autoInject = Object.keys(all_modules);
86}
87
2af86592
SR
88if (program.autoInject) {
89 var temp = require('temp');
2af86592
SR
90 temp.track();
91
92 var template = {
b11bb5c3 93 header: "<html>\n<head>\n<meta charset='utf-8' />\n<link rel='stylesheet' href='" + get_path('node_modules/mocha/mocha.css') + "'/>\n</head>\n<body><div id='mocha'></div>",
8eb88937 94 script_tag: function(p) { return "<script src='" + p + "'></script>"; },
9b731d3a 95 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
96 };
97
b11bb5c3
SR
98 template.header += "\n" + template.script_tag(get_path('node_modules/chai/chai.js'));
99 template.header += "\n" + template.script_tag(get_path('node_modules/mocha/mocha.js'));
100 template.header += "\n" + template.script_tag(get_path('node_modules/sinon/pkg/sinon.js'));
101 template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
102 template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
2af86592
SR
103 template.header += "\n<script>mocha.setup('bdd');</script>";
104
105
106 template.header = program.autoInject.reduce(function(acc, sn) {
b11bb5c3 107 return acc + "\n" + template.script_tag(get_path_cwd(sn));
2af86592
SR
108 }, template.header);
109
110 file_paths = program.tests.map(function(jsn, ind) {
111 var templ = template.header;
112 templ += "\n";
b11bb5c3 113 templ += template.script_tag(get_path_cwd(jsn));
2af86592
SR
114 templ += template.footer;
115
116 var tempfile = temp.openSync({ prefix: 'novnc-zombie-inject-', suffix: '-file_num-'+ind+'.html' });
117 fs.writeSync(tempfile.fd, templ);
118 fs.closeSync(tempfile.fd);
119 return tempfile.path;
120 });
121
122}
123else {
124 file_paths = program.tests.map(function(fn) {
125 return path.resolve(process.cwd(), fn);
126 });
127}
128
2af86592
SR
129var use_ansi = false;
130if (program.color) use_ansi = true;
131else if (program.disableColor) use_ansi = false;
132else if (process.stdout.isTTY) use_ansi = true;
133
134var cursor = ansi(process.stdout, { enabled: use_ansi });
135
1e570156 136if (program.outputHtml) {
1e570156
SR
137 file_paths.forEach(function(path, path_ind) {
138 fs.readFile(path, function(err, data) {
139 if (err) {
140 console.warn(error.stack);
141 return;
142 }
8eb88937 143
b11bb5c3
SR
144 if (use_ansi) {
145 cursor
146 .bold()
147 .write(program.tests[path_ind])
148 .reset()
149 .write("\n")
150 .write(Array(program.tests[path_ind].length+1).join('='))
151 .write("\n\n");
152 }
153
1e570156 154 cursor
1e570156 155 .write(data)
b11bb5c3 156 .write("\n\n");
1e570156
SR
157 });
158 });
159}
160
161if (program.generateHtml) {
4a4643c0
SR
162 var open_browser;
163 if (program.openInBrowser) {
164 open_browser = require('open');
165 }
166
1e570156
SR
167 file_paths.forEach(function(path, path_ind) {
168 cursor
169 .bold()
170 .write(program.tests[path_ind])
171 .write(": ")
172 .reset()
173 .write(path)
174 .write("\n");
4a4643c0
SR
175
176 if (program.openInBrowser) {
177 open_browser(path);
178 }
1e570156 179 });
2af86592 180 console.log('');
1e570156 181}
2af86592 182
1e570156
SR
183if (program.generateHtml) {
184 process.stdin.resume(); // pause until C-c
185 process.on('SIGINT', function() {
186 process.stdin.pause(); // exit
187 });
188}
2af86592 189
1e570156
SR
190if (!program.outputHtml && !program.generateHtml) {
191 var failure_count = 0;
2af86592 192
1e570156 193 var prov = require(path.resolve(__dirname, 'run_from_console.'+program.provider+'.js'));
2af86592 194
2af86592 195 cursor
1e570156
SR
196 .write("Running tests ")
197 .bold()
198 .write(program.tests.join(', '))
2af86592 199 .reset()
1e570156
SR
200 .grey()
201 .write(' using provider '+prov.name)
2af86592 202 .reset()
1e570156
SR
203 .write("\n");
204 //console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name);
2af86592 205
07f514d8 206 var provider = prov.provide_emitter(file_paths, program.debugger);
1e570156
SR
207 provider.on('test_ready', function(test_json) {
208 console.log('');
2af86592 209
1e570156 210 filename = program.tests[test_json.file_ind];
2af86592 211
1e570156
SR
212 cursor.bold();
213 console.log('Results for %s:', filename);
214 console.log(Array('Results for :'.length+filename.length+1).join('='));
215 cursor.reset();
2af86592 216
1e570156
SR
217 console.log('');
218
1e570156 219 cursor
8eb88937 220 .write(''+test_json.num_tests+' tests run, ')
1e570156
SR
221 .green()
222 .write(''+test_json.num_passes+' passed');
223 if (test_json.num_slow > 0) {
224 cursor
225 .reset()
226 .write(' (');
227 cursor
228 .yellow()
229 .write(''+test_json.num_slow+' slow')
230 .reset()
231 .write(')');
232 }
233 cursor
234 .reset()
235 .write(', ');
236 cursor
237 .red()
238 .write(''+test_json.num_fails+' failed');
8eb88937
SR
239 if (test_json.num_skipped > 0) {
240 cursor
241 .reset()
242 .write(', ')
243 .grey()
244 .write(''+test_json.num_skipped+' skipped');
245 }
1e570156
SR
246 cursor
247 .reset()
8eb88937 248 .write(' -- duration: '+test_json.duration+"s\n");
1e570156
SR
249
250 console.log('');
251
252 if (test_json.num_fails > 0 || program.printAll) {
b0b5fc55
SR
253 var extract_error_lines = function (err) {
254 // the split is to avoid a weird thing where in PhantomJS where we get a stack trace too
255 var err_lines = err.split('\n');
256 if (err_lines.length == 1) {
257 return err_lines[0];
258 } else {
259 var ind;
260 for (ind = 0; ind < err_lines.length; ind++) {
261 var at_ind = err_lines[ind].trim().indexOf('at ');
262 if (at_ind === 0) {
263 break;
264 }
265 }
266
267 return err_lines.slice(0, ind).join('\n');
268 }
269 };
270
1e570156
SR
271 var traverse_tree = function(indentation, node) {
272 if (node.type == 'suite') {
273 if (!node.has_subfailures && !program.printAll) return;
274
8eb88937 275 if (indentation === 0) {
1e570156
SR
276 cursor.bold();
277 console.log(node.name);
278 console.log(Array(node.name.length+1).join('-'));
279 cursor.reset();
280 }
281 else {
282 cursor
283 .write(Array(indentation+3).join('#'))
284 .bold()
285 .write(' '+node.name+' ')
286 .reset()
287 .write(Array(indentation+3).join('#'))
288 .write("\n");
289 }
2af86592 290
2af86592 291 console.log('');
1e570156
SR
292
293 for (var i = 0; i < node.children.length; i++) {
294 traverse_tree(indentation+1, node.children[i]);
295 }
2af86592 296 }
1e570156
SR
297 else {
298 if (!node.pass) {
299 cursor.magenta();
300 console.log('- failed: '+node.text+test_json.replay);
301 cursor.red();
b0b5fc55 302 console.log(' '+extract_error_lines(node.error));
1e570156
SR
303 cursor.reset();
304 console.log('');
305 }
306 else if (program.printAll) {
8eb88937
SR
307 if (node.skipped) {
308 cursor
309 .grey()
310 .write('- skipped: '+node.text);
311 }
312 else {
313 if (node.slow) cursor.yellow();
314 else cursor.green();
315
316 cursor
317 .write('- pass: '+node.text)
318 .grey()
319 .write(' ('+node.duration+') ');
320 }
1e570156
SR
321 /*if (node.slow) cursor.yellow();
322 else cursor.green();*/
323 cursor
324 //.write(test_json.replay)
325 .reset()
326 .write("\n");
327 console.log('');
328 }
2af86592 329 }
8eb88937 330 };
2af86592 331
1e570156
SR
332 for (var i = 0; i < test_json.suites.length; i++) {
333 traverse_tree(0, test_json.suites[i]);
334 }
2af86592 335 }
2af86592 336
8eb88937 337 if (test_json.num_fails === 0) {
1e570156
SR
338 cursor.fg.green();
339 console.log('all tests passed :-)');
340 cursor.reset();
341 }
342 });
2af86592 343
8eb88937
SR
344 if (program.debug) {
345 provider.on('console', function(line) {
93af721a
SR
346 // log to stderr
347 console.error(line);
8eb88937
SR
348 });
349 }
2af86592 350
93af721a
SR
351 provider.on('error', function(line) {
352 // log to stderr
353 console.error('ERROR: ' + line);
354 });
355
1e570156
SR
356 /*gprom.finally(function(ph) {
357 ph.exit();
358 // exit with a status code that actually gives information
359 if (program.exitWithFailureCount) process.exit(failure_count);
360 });*/
361}