├── .gitignore ├── package.json ├── README.md └── reporter.js /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | node_modules 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "karma-verbose-reporter", 3 | "version": "0.0.8", 4 | "description": "A Karma reporter bringing verbosity to the max.", 5 | "main": "reporter.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/usrz/javascript-karma-verbose-reporter.git" 9 | }, 10 | "keywords": [ 11 | "karma-plugin", 12 | "karma-reporter" 13 | ], 14 | "author": { 15 | "name": "Pier Fumagalli", 16 | "email": "pier@usrz.com" 17 | }, 18 | "contributors": [{ 19 | "name": "Lucas G. Sánchez", 20 | "email": "unkiwii@gmail.com" 21 | }], 22 | "dependencies": { 23 | "colors": "1.4.0" 24 | }, 25 | "peerDependencies": { 26 | "karma": ">=0.12" 27 | }, 28 | "license": "MIT" 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Karma (very) Verbose Reporter 2 | ============================= 3 | 4 | To install, just get the tarball from GitHub via NPM: 5 | 6 | ``` 7 | npm install --save-dev karma-verbose-reporter 8 | ``` 9 | 10 | This reporter logs everything emitted during the test phase: 11 | 12 | ``` 13 | ... 14 | INFO [Safari 8.0.0 (Mac OS X 10.10) | hash, SHA-256 | should hash empty data]: Success: 4 ms 15 | INFO [Safari 8.0.0 (Mac OS X 10.10) | hash, SHA-256 | should hash a well-known string]: Success: 9 ms 16 | INFO [Firefox 33.0.0 (Mac OS X 10.10) | decode, UTF8 | decode]: Success: 9 ms 17 | INFO [Safari 8.0.0 (Mac OS X 10.10) | hash, SHA-256 | should hash 10k of binary data]: Success: 13 ms 18 | INFO [Firefox 33.0.0 (Mac OS X 10.10) | decode, HEX | decode lower case]: Success: 10 ms 19 | INFO [PhantomJS 1.9.7 (Mac OS X) | defer | should reject a wrapped rejected promise]: Success: 35 ms 20 | INFO [Safari 8.0.0 (Mac OS X 10.10) | hash, SHA-384 | should hash empty data]: Success: 3 ms 21 | INFO [Safari 8.0.0 (Mac OS X 10.10) | hash, SHA-384 | should hash a well-known string]: Success: 7 ms 22 | INFO [Firefox 33.0.0 (Mac OS X 10.10) | decode, HEX | decode upper case]: Success: 11 ms 23 | ... 24 | ``` 25 | 26 | Reports are also quite detailed: 27 | 28 | ``` 29 | Suites and tests results: 30 | 31 | - decode : 32 | * should exist : 4 ok 33 | * should fail decoding garbage : 4 ok 34 | * should fail decoding null data : 4 ok 35 | * should fail decoding with unknown algorithm : 4 ok 36 | * should handle nested promises : 4 ok 37 | - BASE64 : 38 | * decode : 4 ok 39 | - HEX : 40 | * decode lower case : 4 ok 41 | * decode upper case : 4 ok 42 | - UTF8 : 43 | * decode : 4 ok 44 | - defer : 45 | * should defer a static value : 4 ok 46 | * should exist : 4 ok 47 | * should reject a thrown error : 4 ok 48 | * should reject a thrown string : 4 ok 49 | * should reject a wrapped rejected promise : 4 ok 50 | * should resolve a deferred function : 4 ok 51 | * should resolve a wrapped resolved promise : 4 ok 52 | - encode : 53 | * should exist : 4 ok 54 | * should fail encoding garbage : 4 ok 55 | * should fail encoding null data : 4 ok 56 | * should fail encoding with unknown algorithm : 4 ok 57 | * should handle nested promises : 4 ok 58 | - BASE64 : 59 | * encode : 4 ok 60 | - HEX : 61 | * encode : 4 ok 62 | - UTF8 : 63 | * encode Uint8Array : 4 ok 64 | * encode plain array : 4 ok 65 | * encode string (pass-through) : 4 ok 66 | - hash : 67 | * should exist : 4 ok 68 | - SHA-1 : 69 | * should hash 10k of binary data : 4 ok 70 | * should hash a well-known string : 4 ok 71 | * should hash empty data : 4 ok 72 | - SHA-224 : 73 | * should hash 10k of binary data : 4 ok 74 | * should hash a well-known string : 4 ok 75 | * should hash empty data : 4 ok 76 | - SHA-256 : 77 | * should hash 10k of binary data : 4 ok 78 | * should hash a well-known string : 4 ok 79 | * should hash empty data : 4 ok 80 | - SHA-384 : 81 | * should hash 10k of binary data : 4 ok 82 | * should hash a well-known string : 4 ok 83 | * should hash empty data : 4 ok 84 | - SHA-512 : 85 | * should hash 10k of binary data : 4 ok 86 | * should hash a well-known string : 4 ok 87 | * should hash empty data : 4 ok 88 | - subtle : 89 | * should digest : 2 ok, 2 skipped 90 | * should exist : 4 ok 91 | 92 | Browser results: 93 | 94 | - Safari 8.0.0 (Mac OS X 10.10): 44 tests 95 | - 44 ok 96 | - Chrome 39.0.2171 (Mac OS X 10.10.0): 44 tests 97 | - 44 ok 98 | - PhantomJS 1.9.7 (Mac OS X): 44 tests 99 | - 43 ok, 1 skipped 100 | - Firefox 33.0.0 (Mac OS X 10.10): 44 tests 101 | - 43 ok, 1 skipped 102 | ``` 103 | -------------------------------------------------------------------------------- /reporter.js: -------------------------------------------------------------------------------- 1 | require('colors'); 2 | var util = require('util'); 3 | 4 | function VerboseReporter(logger, config) { 5 | 6 | /* 7 | * Known events: 8 | * 9 | * - run_start 10 | * - run_complete 11 | * 12 | * - browser_complete 13 | * - browser_error 14 | * - browser_log 15 | * - browser_process_failure 16 | * - browser_register 17 | * - browser_start 18 | * - browsers_change 19 | * - exit 20 | * - file_list_modified 21 | * - spec_complete 22 | */ 23 | 24 | var _log = logger.create('report'); 25 | var _browsers = null; 26 | var _tests = null; 27 | var _startTime = new Date(); 28 | /* ======================================================================== */ 29 | /* INTERNAL FUNCTIONS */ 30 | /* ======================================================================== */ 31 | 32 | function print() { 33 | process.stdout.write(util.format.apply(this, arguments)); 34 | process.stdout.write('\n'); 35 | } 36 | 37 | function forBrowser(browser) { 38 | /* onBrowserLog might arrive before onBrowserStart, sooo */ 39 | if (_browsers[browser.id]) return _browsers[browser.id]; 40 | return _browsers[browser.id] = { 41 | "name": browser.name, 42 | "successes": 0, 43 | "failures": 0, 44 | "skipped": 0, 45 | "total": 0, 46 | "log": [] 47 | }; 48 | } 49 | 50 | function message(result) { 51 | if (result.total > 0) { 52 | if (result.total == 1) { 53 | var message = []; 54 | if (result.successes) message.push("ok".green); 55 | if (result.failures) message.push("failed".red); 56 | if (result.skipped) message.push("skipped".yellow); 57 | return message.join(' '); 58 | } else { 59 | var message = []; 60 | if (result.successes) message.push((result.successes + " ok").green); 61 | if (result.failures) message.push((result.failures + " failed").red); 62 | if (result.skipped) message.push((result.skipped + " skipped").yellow); 63 | return message.join(', '); 64 | } 65 | } else { 66 | return "no tests".magenta; 67 | } 68 | } 69 | 70 | function getElapsedTime() { 71 | var msec = (new Date() - _startTime); 72 | var hh = Math.floor(msec / 1000 / 60 / 60); 73 | msec -= hh * 1000 * 60 * 60; 74 | var mm = Math.floor(msec / 1000 / 60); 75 | msec -= mm * 1000 * 60; 76 | var ss = Math.floor(msec / 1000); 77 | msec -= ss * 1000; 78 | return "Elapsed Time: " + mm + ":" + ss + ":" + msec + " min/sec/ms"; 79 | } 80 | 81 | function report(tests, indent) { 82 | if (! tests) return; 83 | indent = indent || ''; 84 | 85 | if (tests.results) { 86 | var results = Object.keys(tests.results); 87 | for (var i in results) { 88 | var result = tests.results[results[i]]; 89 | print(indent, '*', results[i], ':', message(result)); 90 | } 91 | } 92 | 93 | if (tests.suites) { 94 | var suites = Object.keys(tests.suites); 95 | for (var i in suites) { 96 | print(indent, '-', suites[i].bold, ':'); 97 | report(tests.suites[suites[i]], ' ' + indent); 98 | } 99 | } 100 | 101 | }; 102 | 103 | /* ======================================================================== */ 104 | /* RUN START/COMPLETE */ 105 | /* ======================================================================== */ 106 | 107 | this.onRunStart = function(browsers) { 108 | _browsers = {}; 109 | _tests = {suites: {}}; 110 | }; 111 | 112 | this.onRunComplete = function(browsers, results) { 113 | 114 | for (var i in _browsers) { 115 | var browser = _browsers[i]; 116 | var log = logger.create(browser.name); 117 | browser.log.forEach(function(entry) { 118 | (log[entry.level] || log.info).call(log, entry.message); 119 | }); 120 | browser.log = []; 121 | } 122 | 123 | print("\n"); 124 | print("Suites and tests results:".bold.underline); 125 | print(); 126 | report(_tests); 127 | 128 | print(); 129 | print("Browser results:".bold.underline) 130 | print(); 131 | 132 | for (var i in _browsers) { 133 | var browser = _browsers[i]; 134 | print(" - " + browser.name.bold + ": " + browser.total + " tests"); 135 | print(" - " + message(browser)); 136 | } 137 | print(getElapsedTime()); 138 | print(); 139 | }; 140 | 141 | /* ======================================================================== */ 142 | /* BROWSER START/LOG/ERROR */ 143 | /* ======================================================================== */ 144 | 145 | this.onBrowserStart = function(browser) { 146 | logger.create(browser.name).info("Starting tests", browser.id); 147 | }; 148 | 149 | this.onBrowserLog = function(browser, message, level) { 150 | if (level == 'log') level = 'info'; 151 | if (config && config.immediateLogs) { 152 | var log = logger.create(browser.name); 153 | (log[level] || log.info).call(log, message); 154 | } else { 155 | forBrowser(browser).log.push({level: level, message: message}); 156 | } 157 | }; 158 | 159 | this.onBrowserError = function(browser, error) { 160 | logger.create(browser.name).error(error); 161 | }; 162 | 163 | this.onSpecComplete = function(browser, result) { 164 | var suite = ''; 165 | var tests = _tests; 166 | var b = forBrowser(browser); 167 | 168 | for (var i in result.suite) { 169 | var suiteName = result.suite[i]; 170 | suite += (', ' + suiteName); 171 | 172 | if (! tests.suites) tests.suites = {}; 173 | if (! tests.suites[suiteName]) tests.suites[suiteName] = {}; 174 | tests = tests.suites[suiteName]; 175 | } 176 | 177 | suite = suite.length > 2 ? ' | ' + suite.substring(2) + ' | ' : ' | '; 178 | 179 | var log = logger.create(browser.name + suite + result.description); 180 | 181 | b.log.forEach(function(entry) { 182 | (log[entry.level] || log.info).call(log, entry.message); 183 | }); 184 | b.log = []; 185 | 186 | if (! tests.results) tests.results = {}; 187 | if (! tests.results[result.description]) { 188 | tests.results[result.description] = { 189 | "successes": 0, 190 | "failures": 0, 191 | "skipped": 0, 192 | "total": 0 193 | }; 194 | } 195 | var results = tests.results[result.description]; 196 | 197 | b.total ++; 198 | results.total ++; 199 | 200 | if (result.skipped) { 201 | b.skipped ++; 202 | results.skipped ++; 203 | log.warn('Test skipped'); 204 | } else if (result.success) { 205 | b.successes ++; 206 | results.successes ++; 207 | log.info('Success: ' + result.time + ' ms'); 208 | print("Test Num: ".bold.yellow + (b.total + "").bold.yellow); 209 | print(getElapsedTime().bold.blue); 210 | } else { 211 | b.failures ++; 212 | results.failures ++; 213 | for (var i in result.log) { 214 | log.error(result.log[i]); 215 | } 216 | } 217 | }; 218 | 219 | this.adapters = []; 220 | } 221 | 222 | /* ========================================================================== */ 223 | /* MODULE DECLARATION */ 224 | /* ========================================================================== */ 225 | 226 | VerboseReporter.$inject = ['logger', 'config.verboseReporter']; 227 | 228 | module.exports = { 229 | 'reporter:verbose': ['type', VerboseReporter] 230 | }; 231 | --------------------------------------------------------------------------------