]> git.proxmox.com Git - mirror_novnc.git/blame - tests/run_from_console.js
Add support for Travis CI and SauceLabs Testing
[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).')
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
24if (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
30var file_paths = [];
31
85e89916
SR
32var all_js = program.tests.reduce(function(a,e) { return a && e.slice(-3) == '.js'; }, true);
33
34if (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
65if (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}
100else {
101 file_paths = program.tests.map(function(fn) {
102 return path.resolve(process.cwd(), fn);
103 });
104}
105
2af86592
SR
106var use_ansi = false;
107if (program.color) use_ansi = true;
108else if (program.disableColor) use_ansi = false;
109else if (process.stdout.isTTY) use_ansi = true;
110
111var cursor = ansi(process.stdout, { enabled: use_ansi });
112
1e570156 113if (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
134if (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
156if (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
163if (!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}