konacha 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,70 +1,37 @@
1
- (function () {
2
- window.Konacha = {
3
- dots:"",
1
+ window.Konacha = {
2
+ dots:"",
4
3
 
5
- Reporter:function (runner) {
6
- window.mocha.reporters.Base.call(this, runner);
4
+ Reporter:function (runner) {
5
+ window.mocha.reporters.Base.call(this, runner);
7
6
 
8
- runner.on('start', function () {
9
- Konacha.results = [];
10
- });
11
-
12
- runner.on('pass', function (test) {
13
- Konacha.dots += ".";
14
- Konacha.results.push({
15
- name: test.title,
16
- passed: true
17
- });
18
- });
7
+ runner.on('start', function () {
8
+ Konacha.results = [];
9
+ });
19
10
 
20
- runner.on('fail', function (test) {
21
- Konacha.dots += "F";
22
- Konacha.results.push({
23
- name: test.title,
24
- passed: false,
25
- message: test.err.message,
26
- trace: test.err.stack
27
- });
11
+ runner.on('pass', function (test) {
12
+ Konacha.dots += ".";
13
+ Konacha.results.push({
14
+ name:test.title,
15
+ passed:true
28
16
  });
29
-
30
- runner.on('end', function () {
31
- Konacha.done = true;
17
+ });
18
+
19
+ runner.on('fail', function (test) {
20
+ Konacha.dots += "F";
21
+ Konacha.results.push({
22
+ name:test.title,
23
+ passed:false,
24
+ message:test.err.message,
25
+ trace:test.err.stack
32
26
  });
33
- },
27
+ });
34
28
 
35
- getResults:function () {
36
- return JSON.stringify(Konacha.results);
37
- }
38
- };
29
+ runner.on('end', function () {
30
+ Konacha.done = true;
31
+ });
32
+ },
39
33
 
40
- var suite = new mocha.Suite
41
- , utils = mocha.utils
42
- , Reporter = Konacha.Reporter;
43
-
44
- function parse(qs) {
45
- return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
46
- var i = pair.indexOf('=')
47
- , key = pair.slice(0, i)
48
- , val = pair.slice(++i);
49
-
50
- obj[key] = decodeURIComponent(val);
51
- return obj;
52
- }, {});
34
+ getResults:function () {
35
+ return JSON.stringify(Konacha.results);
53
36
  }
54
-
55
- mocha.setup = function (ui) {
56
- ui = mocha.interfaces[ui];
57
- if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
58
- ui(suite);
59
- suite.emit('pre-require', window);
60
- };
61
-
62
- mocha.run = function () {
63
- suite.emit('run');
64
- var runner = new mocha.Runner(suite);
65
- var reporter = new Reporter(runner);
66
- var query = parse(window.location.search || "");
67
- if (query.grep) runner.grep(new RegExp(query.grep));
68
- return runner.run();
69
- };
70
- })();
37
+ };
@@ -0,0 +1,3 @@
1
+ window.Konacha = {
2
+ Reporter: mocha.reporters.HTML
3
+ };
@@ -57,6 +57,10 @@ module.exports = function(type){
57
57
  };
58
58
  }); // module: browser/debug.js
59
59
 
60
+ require.register("browser/diff.js", function(module, exports, require){
61
+
62
+ }); // module: browser/diff.js
63
+
60
64
  require.register("browser/events.js", function(module, exports, require){
61
65
 
62
66
  /**
@@ -386,6 +390,65 @@ exports.getWindowSize = function(){
386
390
  };
387
391
  }); // module: browser/tty.js
388
392
 
393
+ require.register("context.js", function(module, exports, require){
394
+
395
+ /**
396
+ * Expose `Context`.
397
+ */
398
+
399
+ module.exports = Context;
400
+
401
+ /**
402
+ * Initialize a new `Context`.
403
+ *
404
+ * @api private
405
+ */
406
+
407
+ function Context(){}
408
+
409
+ /**
410
+ * Set the context `Test` to `test`.
411
+ *
412
+ * @param {Test} test
413
+ * @return {Context}
414
+ * @api private
415
+ */
416
+
417
+ Context.prototype.test = function(test){
418
+ this._test = test;
419
+ return this;
420
+ };
421
+
422
+ /**
423
+ * Set test timeout `ms`.
424
+ *
425
+ * @param {Number} ms
426
+ * @return {Context} self
427
+ * @api private
428
+ */
429
+
430
+ Context.prototype.timeout = function(ms){
431
+ this._test.timeout(ms);
432
+ return this;
433
+ };
434
+
435
+ /**
436
+ * Inspect the context void of `._test`.
437
+ *
438
+ * @return {String}
439
+ * @api private
440
+ */
441
+
442
+ Context.prototype.inspect = function(){
443
+ return JSON.stringify(this, function(key, val){
444
+ return '_test' == key
445
+ ? undefined
446
+ : val;
447
+ }, 2);
448
+ };
449
+
450
+ }); // module: context.js
451
+
389
452
  require.register("hook.js", function(module, exports, require){
390
453
 
391
454
  /**
@@ -410,6 +473,7 @@ module.exports = Hook;
410
473
 
411
474
  function Hook(title, fn) {
412
475
  Runnable.call(this, title, fn);
476
+ this.type = 'hook';
413
477
  }
414
478
 
415
479
  /**
@@ -453,6 +517,11 @@ module.exports = function(suite){
453
517
 
454
518
  suite.on('pre-require', function(context){
455
519
 
520
+ // noop variants
521
+
522
+ context.xdescribe = function(){};
523
+ context.xit = function(){};
524
+
456
525
  /**
457
526
  * Execute before running tests.
458
527
  */
@@ -789,12 +858,13 @@ require.register("mocha.js", function(module, exports, require){
789
858
  * Library version.
790
859
  */
791
860
 
792
- exports.version = '0.12.0';
861
+ exports.version = '0.14.0';
793
862
 
794
863
  exports.utils = require('./utils');
795
864
  exports.interfaces = require('./interfaces');
796
865
  exports.reporters = require('./reporters');
797
866
  exports.Runnable = require('./runnable');
867
+ exports.Context = require('./context');
798
868
  exports.Runner = require('./runner');
799
869
  exports.Suite = require('./suite');
800
870
  exports.Hook = require('./hook');
@@ -808,7 +878,8 @@ require.register("reporters/base.js", function(module, exports, require){
808
878
  * Module dependencies.
809
879
  */
810
880
 
811
- var tty = require('browser/tty');
881
+ var tty = require('browser/tty')
882
+ , diff = require('browser/diff');
812
883
 
813
884
  /**
814
885
  * Check if both stdio streams are associated with a tty.
@@ -849,6 +920,9 @@ exports.colors = {
849
920
  , 'slow': 31
850
921
  , 'green': 32
851
922
  , 'light': 90
923
+ , 'diff gutter': 90
924
+ , 'diff added': 42
925
+ , 'diff removed': 41
852
926
  };
853
927
 
854
928
  /**
@@ -936,7 +1010,41 @@ exports.list = function(failures){
936
1010
  , message = err.message || ''
937
1011
  , stack = err.stack || message
938
1012
  , index = stack.indexOf(message) + message.length
939
- , msg = stack.slice(0, index);
1013
+ , msg = stack.slice(0, index)
1014
+ , actual = err.actual
1015
+ , expected = err.expected;
1016
+
1017
+ // actual / expected diff
1018
+ if ('string' == typeof actual && 'string' == typeof expected) {
1019
+ var len = Math.max(actual.length, expected.length);
1020
+
1021
+ if (len < 20) msg = errorDiff(err, 'Chars');
1022
+ else msg = errorDiff(err, 'Words');
1023
+
1024
+ // linenos
1025
+ var lines = msg.split('\n');
1026
+ if (lines.length > 4) {
1027
+ var width = String(lines.length).length;
1028
+ msg = lines.map(function(str, i){
1029
+ return pad(++i, width) + ' |' + ' ' + str;
1030
+ }).join('\n');
1031
+ }
1032
+
1033
+ // legend
1034
+ msg = '\n'
1035
+ + color('diff removed', 'actual')
1036
+ + ' '
1037
+ + color('diff added', 'expected')
1038
+ + '\n\n'
1039
+ + msg
1040
+ + '\n';
1041
+
1042
+ // indent
1043
+ msg = msg.replace(/^/gm, ' ');
1044
+
1045
+ fmt = color('error title', ' %s) %s:\n%s')
1046
+ + color('error stack', '\n%s\n');
1047
+ }
940
1048
 
941
1049
  // indent stack trace without msg
942
1050
  stack = stack.slice(index + 1)
@@ -1040,6 +1148,51 @@ Base.prototype.epilogue = function(){
1040
1148
  console.log();
1041
1149
  };
1042
1150
 
1151
+ /**
1152
+ * Pad the given `str` to `len`.
1153
+ *
1154
+ * @param {String} str
1155
+ * @param {String} len
1156
+ * @return {String}
1157
+ * @api private
1158
+ */
1159
+
1160
+ function pad(str, len) {
1161
+ str = String(str);
1162
+ return Array(len - str.length + 1).join(' ') + str;
1163
+ }
1164
+
1165
+ /**
1166
+ * Return a character diff for `err`.
1167
+ *
1168
+ * @param {Error} err
1169
+ * @return {String}
1170
+ * @api private
1171
+ */
1172
+
1173
+ function errorDiff(err, type) {
1174
+ return diff['diff' + type](err.actual, err.expected).map(function(str){
1175
+ if (str.added) return colorLines('diff added', str.value);
1176
+ if (str.removed) return colorLines('diff removed', str.value);
1177
+ return str.value;
1178
+ }).join('');
1179
+ }
1180
+
1181
+ /**
1182
+ * Color lines for `str`, using the color `name`.
1183
+ *
1184
+ * @param {String} name
1185
+ * @param {String} str
1186
+ * @return {String}
1187
+ * @api private
1188
+ */
1189
+
1190
+ function colorLines(name, str) {
1191
+ return str.split('\n').map(function(str){
1192
+ return color(name, str);
1193
+ }).join('\n');
1194
+ }
1195
+
1043
1196
  }); // module: reporters/base.js
1044
1197
 
1045
1198
  require.register("reporters/doc.js", function(module, exports, require){
@@ -1186,6 +1339,53 @@ Dot.prototype.constructor = Dot;
1186
1339
 
1187
1340
  }); // module: reporters/dot.js
1188
1341
 
1342
+ require.register("reporters/html-cov.js", function(module, exports, require){
1343
+
1344
+ /**
1345
+ * Module dependencies.
1346
+ */
1347
+
1348
+ var JSONCov = require('./json-cov')
1349
+ , fs = require('browser/fs');
1350
+
1351
+ /**
1352
+ * Expose `HTMLCov`.
1353
+ */
1354
+
1355
+ exports = module.exports = HTMLCov;
1356
+
1357
+ /**
1358
+ * Initialize a new `JsCoverage` reporter.
1359
+ *
1360
+ * @param {Runner} runner
1361
+ * @api public
1362
+ */
1363
+
1364
+ function HTMLCov(runner) {
1365
+ var jade = require('jade')
1366
+ , file = __dirname + '/templates/coverage.jade'
1367
+ , str = fs.readFileSync(file, 'utf8')
1368
+ , fn = jade.compile(str, { filename: file })
1369
+ , self = this;
1370
+
1371
+ JSONCov.call(this, runner, false);
1372
+
1373
+ runner.on('end', function(){
1374
+ process.stdout.write(fn({
1375
+ cov: self.cov
1376
+ , coverageClass: coverageClass
1377
+ }));
1378
+ });
1379
+ }
1380
+
1381
+ function coverageClass(n) {
1382
+ if (n >= 75) return 'high';
1383
+ if (n >= 50) return 'medium';
1384
+ if (n >= 25) return 'low';
1385
+ return 'terrible';
1386
+ }
1387
+ }); // module: reporters/html-cov.js
1388
+
1189
1389
  require.register("reporters/html.js", function(module, exports, require){
1190
1390
 
1191
1391
  /**
@@ -1224,15 +1424,17 @@ var statsTemplate = '<ul id="stats">'
1224
1424
  function HTML(runner) {
1225
1425
  Base.call(this, runner);
1226
1426
 
1227
- // TODO: clean up
1228
-
1229
1427
  var self = this
1230
1428
  , stats = this.stats
1231
1429
  , total = runner.total
1232
- , root = $('#mocha')
1430
+ , root = document.getElementById('mocha')
1431
+ , stat = fragment(statsTemplate)
1432
+ , items = stat.getElementsByTagName('li')
1433
+ , passes = items[1].getElementsByTagName('em')[0]
1434
+ , failures = items[2].getElementsByTagName('em')[0]
1435
+ , duration = items[3].getElementsByTagName('em')[0]
1436
+ , canvas = stat.getElementsByTagName('canvas')[0]
1233
1437
  , stack = [root]
1234
- , stat = $(statsTemplate).appendTo(root)
1235
- , canvas = stat.find('canvas').get(0)
1236
1438
  , progress
1237
1439
  , ctx
1238
1440
 
@@ -1241,7 +1443,9 @@ function HTML(runner) {
1241
1443
  progress = new Progress;
1242
1444
  }
1243
1445
 
1244
- if (!root.length) return error('#mocha div missing, add it to your document');
1446
+ if (!root) return error('#mocha div missing, add it to your document');
1447
+
1448
+ root.appendChild(stat);
1245
1449
 
1246
1450
  if (progress) progress.size(40);
1247
1451
 
@@ -1249,12 +1453,12 @@ function HTML(runner) {
1249
1453
  if (suite.root) return;
1250
1454
 
1251
1455
  // suite
1252
- var el = $('<div class="suite"><h1>' + suite.title + '</h1></div>');
1456
+ var el = fragment('<div class="suite"><h1>%s</h1></div>', suite.title);
1253
1457
 
1254
1458
  // container
1255
- stack[0].append(el);
1256
- stack.unshift($('<div>'));
1257
- el.append(stack[0]);
1459
+ stack[0].appendChild(el);
1460
+ stack.unshift(document.createElement('div'));
1461
+ el.appendChild(stack[0]);
1258
1462
  });
1259
1463
 
1260
1464
  runner.on('suite end', function(suite){
@@ -1269,48 +1473,48 @@ function HTML(runner) {
1269
1473
  runner.on('test end', function(test){
1270
1474
  // TODO: add to stats
1271
1475
  var percent = stats.tests / total * 100 | 0;
1272
-
1273
- if (progress) {
1274
- progress.update(percent).draw(ctx);
1275
- }
1476
+ if (progress) progress.update(percent).draw(ctx);
1276
1477
 
1277
1478
  // update stats
1278
1479
  var ms = new Date - stats.start;
1279
- stat.find('.passes em').text(stats.passes);
1280
- stat.find('.failures em').text(stats.failures);
1281
- stat.find('.duration em').text((ms / 1000).toFixed(2));
1480
+ text(passes, stats.passes);
1481
+ text(failures, stats.failures);
1482
+ text(duration, (ms / 1000).toFixed(2));
1282
1483
 
1283
1484
  // test
1284
- if (test.passed) {
1285
- var el = $('<div class="test pass"><h2>' + escape(test.title) + '</h2></div>')
1485
+ if ('passed' == test.state) {
1486
+ var el = fragment('<div class="test pass"><h2>%e</h2></div>', test.title);
1286
1487
  } else if (test.pending) {
1287
- var el = $('<div class="test pass pending"><h2>' + escape(test.title) + '</h2></div>')
1488
+ var el = fragment('<div class="test pass pending"><h2>%e</h2></div>', test.title);
1288
1489
  } else {
1289
- var el = $('<div class="test fail"><h2>' + escape(test.title) + '</h2></div>');
1490
+ var el = fragment('<div class="test fail"><h2>%e</h2></div>', test.title);
1290
1491
  var str = test.err.stack || test.err;
1291
1492
 
1292
1493
  // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
1293
1494
  // check for the result of the stringifying.
1294
1495
  if ('[object Error]' == str) str = test.err.message;
1295
1496
 
1296
- $('<pre class="error">' + escape(str) + '</pre>').appendTo(el);
1497
+ el.appendChild(fragment('<pre class="error">%e</pre>', str));
1297
1498
  }
1298
1499
 
1299
1500
  // toggle code
1300
- el.find('h2').toggle(function(){
1301
- pre && pre.slideDown('fast');
1302
- }, function(){
1303
- pre && pre.slideUp('fast');
1501
+ var h2 = el.getElementsByTagName('h2')[0];
1502
+
1503
+ on(h2, 'click', function(){
1504
+ pre.style.display = 'none' == pre.style.display
1505
+ ? 'block'
1506
+ : 'none';
1304
1507
  });
1305
1508
 
1306
1509
  // code
1307
1510
  // TODO: defer
1308
1511
  if (!test.pending) {
1309
- var code = escape(clean(test.fn.toString()));
1310
- var pre = $('<pre><code>' + code + '</code></pre>');
1311
- pre.appendTo(el).hide();
1512
+ var pre = fragment('<pre><code>%e</code></pre>', clean(test.fn.toString()));
1513
+ el.appendChild(pre);
1514
+ pre.style.display = 'none';
1312
1515
  }
1313
- stack[0].append(el);
1516
+
1517
+ stack[0].appendChild(el);
1314
1518
  });
1315
1519
  }
1316
1520
 
@@ -1319,7 +1523,50 @@ function HTML(runner) {
1319
1523
  */
1320
1524
 
1321
1525
  function error(msg) {
1322
- $('<div id="error">' + msg + '</div>').appendTo('body');
1526
+ document.body.appendChild(fragment('<div id="error">%s</div>', msg));
1527
+ }
1528
+
1529
+ /**
1530
+ * Return a DOM fragment from `html`.
1531
+ */
1532
+
1533
+ function fragment(html) {
1534
+ var args = arguments
1535
+ , div = document.createElement('div')
1536
+ , i = 1;
1537
+
1538
+ div.innerHTML = html.replace(/%([se])/g, function(_, type){
1539
+ switch (type) {
1540
+ case 's': return String(args[i++]);
1541
+ case 'e': return escape(args[i++]);
1542
+ }
1543
+ });
1544
+
1545
+ return div.firstChild;
1546
+ }
1547
+
1548
+ /**
1549
+ * Set `el` text to `str`.
1550
+ */
1551
+
1552
+ function text(el, str) {
1553
+ if (el.textContent) {
1554
+ el.textContent = str;
1555
+ } else {
1556
+ el.innerText = str;
1557
+ }
1558
+ }
1559
+
1560
+ /**
1561
+ * Listen on `event` with callback `fn`.
1562
+ */
1563
+
1564
+ function on(el, event, fn) {
1565
+ if (el.addEventListener) {
1566
+ el.addEventListener(event, fn, false);
1567
+ } else {
1568
+ el.attachEvent('on' + event, fn);
1569
+ }
1323
1570
  }
1324
1571
 
1325
1572
  /**
@@ -1356,11 +1603,166 @@ exports.List = require('./list');
1356
1603
  exports.Spec = require('./spec');
1357
1604
  exports.Progress = require('./progress');
1358
1605
  exports.Landing = require('./landing');
1606
+ exports.JSONCov = require('./json-cov');
1607
+ exports.HTMLCov = require('./html-cov');
1359
1608
  exports.JSONStream = require('./json-stream');
1360
1609
  exports.XUnit = require('./xunit')
1361
1610
 
1362
1611
  }); // module: reporters/index.js
1363
1612
 
1613
+ require.register("reporters/json-cov.js", function(module, exports, require){
1614
+
1615
+ /**
1616
+ * Module dependencies.
1617
+ */
1618
+
1619
+ var Base = require('./base');
1620
+
1621
+ /**
1622
+ * Expose `JSONCov`.
1623
+ */
1624
+
1625
+ exports = module.exports = JSONCov;
1626
+
1627
+ /**
1628
+ * Initialize a new `JsCoverage` reporter.
1629
+ *
1630
+ * @param {Runner} runner
1631
+ * @param {Boolean} output
1632
+ * @api public
1633
+ */
1634
+
1635
+ function JSONCov(runner, output) {
1636
+ var self = this
1637
+ , output = 1 == arguments.length ? true : output;
1638
+
1639
+ Base.call(this, runner);
1640
+
1641
+ var tests = []
1642
+ , failures = []
1643
+ , passes = [];
1644
+
1645
+ runner.on('test end', function(test){
1646
+ tests.push(test);
1647
+ });
1648
+
1649
+ runner.on('pass', function(test){
1650
+ passes.push(test);
1651
+ });
1652
+
1653
+ runner.on('fail', function(test){
1654
+ failures.push(test);
1655
+ });
1656
+
1657
+ runner.on('end', function(){
1658
+ var cov = global._$jscoverage || {};
1659
+ var result = self.cov = map(cov);
1660
+ result.stats = self.stats;
1661
+ result.tests = tests.map(clean);
1662
+ result.failures = failures.map(clean);
1663
+ result.passes = passes.map(clean);
1664
+ if (!output) return;
1665
+ process.stdout.write(JSON.stringify(result, null, 2 ));
1666
+ });
1667
+ }
1668
+
1669
+ /**
1670
+ * Map jscoverage data to a JSON structure
1671
+ * suitable for reporting.
1672
+ *
1673
+ * @param {Object} cov
1674
+ * @return {Object}
1675
+ * @api private
1676
+ */
1677
+
1678
+ function map(cov) {
1679
+ var ret = {
1680
+ instrumentation: 'node-jscoverage'
1681
+ , sloc: 0
1682
+ , hits: 0
1683
+ , misses: 0
1684
+ , coverage: 0
1685
+ , files: []
1686
+ };
1687
+
1688
+ for (var filename in cov) {
1689
+ var data = coverage(filename, cov[filename]);
1690
+ ret.files.push(data);
1691
+ ret.hits += data.hits;
1692
+ ret.misses += data.misses;
1693
+ ret.sloc += data.sloc;
1694
+ }
1695
+
1696
+ if (ret.sloc > 0) {
1697
+ ret.coverage = (ret.hits / ret.sloc) * 100;
1698
+ }
1699
+
1700
+ return ret;
1701
+ };
1702
+
1703
+ /**
1704
+ * Map jscoverage data for a single source file
1705
+ * to a JSON structure suitable for reporting.
1706
+ *
1707
+ * @param {String} filename name of the source file
1708
+ * @param {Object} data jscoverage coverage data
1709
+ * @return {Object}
1710
+ * @api private
1711
+ */
1712
+
1713
+ function coverage(filename, data) {
1714
+ var ret = {
1715
+ filename: filename,
1716
+ coverage: 0,
1717
+ hits: 0,
1718
+ misses: 0,
1719
+ sloc: 0,
1720
+ source: {}
1721
+ };
1722
+
1723
+ data.source.forEach(function(line, num){
1724
+ num++;
1725
+
1726
+ if (data[num] === 0) {
1727
+ ret.misses++;
1728
+ ret.sloc++;
1729
+ } else if (data[num] !== undefined) {
1730
+ ret.hits++;
1731
+ ret.sloc++;
1732
+ }
1733
+
1734
+ ret.source[num] = {
1735
+ source: line
1736
+ , coverage: data[num] === undefined
1737
+ ? ''
1738
+ : data[num]
1739
+ };
1740
+ });
1741
+
1742
+ ret.coverage = ret.hits / ret.sloc * 100;
1743
+
1744
+ return ret;
1745
+ }
1746
+
1747
+ /**
1748
+ * Return a plain-object representation of `test`
1749
+ * free of cyclic properties etc.
1750
+ *
1751
+ * @param {Object} test
1752
+ * @return {Object}
1753
+ * @api private
1754
+ */
1755
+
1756
+ function clean(test) {
1757
+ return {
1758
+ title: test.title
1759
+ , fullTitle: test.fullTitle()
1760
+ , duration: test.duration
1761
+ }
1762
+ }
1763
+
1764
+ }); // module: reporters/json-cov.js
1765
+
1364
1766
  require.register("reporters/json-stream.js", function(module, exports, require){
1365
1767
 
1366
1768
  /**
@@ -1476,7 +1878,7 @@ function JSONReporter(runner) {
1476
1878
  , passes: passes.map(clean)
1477
1879
  };
1478
1880
 
1479
- process.stdout.write(JSON.stringify(obj));
1881
+ process.stdout.write(JSON.stringify(obj, null, 2));
1480
1882
  });
1481
1883
  }
1482
1884
 
@@ -1568,7 +1970,7 @@ function Landing(runner) {
1568
1970
  : crashed;
1569
1971
 
1570
1972
  // show the crash
1571
- if (test.failed) {
1973
+ if ('failed' == test.state) {
1572
1974
  plane = color('plane crash', '✈');
1573
1975
  crashed = col;
1574
1976
  }
@@ -2048,7 +2450,7 @@ function test(test) {
2048
2450
  , time: test.duration / 1000
2049
2451
  };
2050
2452
 
2051
- if (test.failed) {
2453
+ if ('failed' == test.state) {
2052
2454
  var err = test.err;
2053
2455
  attrs.message = escape(err.message);
2054
2456
  console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
@@ -2117,7 +2519,6 @@ function Runnable(title, fn) {
2117
2519
  this.sync = ! this.async;
2118
2520
  this._timeout = 2000;
2119
2521
  this.timedOut = false;
2120
- this.context = this;
2121
2522
  }
2122
2523
 
2123
2524
  /**
@@ -2196,7 +2597,7 @@ Runnable.prototype.run = function(fn){
2196
2597
  var self = this
2197
2598
  , ms = this.timeout()
2198
2599
  , start = new Date
2199
- , ctx = this.context
2600
+ , ctx = this.ctx
2200
2601
  , finished
2201
2602
  , emitted;
2202
2603
 
@@ -2376,7 +2777,7 @@ Runner.prototype.checkGlobals = function(test){
2376
2777
 
2377
2778
  Runner.prototype.fail = function(test, err){
2378
2779
  ++this.failures;
2379
- test.failed = true;
2780
+ test.state = 'failed';
2380
2781
  this.emit('fail', test, err);
2381
2782
  };
2382
2783
 
@@ -2417,7 +2818,7 @@ Runner.prototype.hook = function(name, fn){
2417
2818
  var hook = hooks[i];
2418
2819
  if (!hook) return fn();
2419
2820
  self.currentRunnable = hook;
2420
- hook.context = self.test;
2821
+ hook.ctx.test(self.test);
2421
2822
 
2422
2823
  self.emit('hook', hook);
2423
2824
 
@@ -2526,6 +2927,7 @@ Runner.prototype.runTest = function(fn){
2526
2927
  , self = this;
2527
2928
 
2528
2929
  try {
2930
+ test.ctx.test(test);
2529
2931
  test.on('error', function(err){
2530
2932
  self.fail(test, err);
2531
2933
  });
@@ -2582,7 +2984,7 @@ Runner.prototype.runTests = function(suite, fn){
2582
2984
  return self.hookUp('afterEach', next);
2583
2985
  }
2584
2986
 
2585
- test.passed = true;
2987
+ test.state = 'passed';
2586
2988
  self.emit('pass', test);
2587
2989
  self.emit('test end', test);
2588
2990
  self.hookUp('afterEach', next);
@@ -2639,7 +3041,7 @@ Runner.prototype.runSuite = function(suite, fn){
2639
3041
  Runner.prototype.uncaught = function(err){
2640
3042
  debug('uncaught exception');
2641
3043
  var runnable = this.currentRunnable;
2642
- if (runnable.failed) return;
3044
+ if ('failed' == runnable.state) return;
2643
3045
  runnable.clearTimeout();
2644
3046
  err.uncaught = true;
2645
3047
  this.fail(runnable, err);
@@ -2725,7 +3127,7 @@ exports = module.exports = Suite;
2725
3127
  */
2726
3128
 
2727
3129
  exports.create = function(parent, title){
2728
- var suite = new Suite(title);
3130
+ var suite = new Suite(title, parent.ctx);
2729
3131
  suite.parent = parent;
2730
3132
  title = suite.fullTitle();
2731
3133
  parent.addSuite(suite);
@@ -2733,14 +3135,17 @@ exports.create = function(parent, title){
2733
3135
  };
2734
3136
 
2735
3137
  /**
2736
- * Initialize a new `Suite` with the given `title`.
3138
+ * Initialize a new `Suite` with the given
3139
+ * `title` and `ctx`.
2737
3140
  *
2738
3141
  * @param {String} title
3142
+ * @param {Context} ctx
2739
3143
  * @api private
2740
3144
  */
2741
3145
 
2742
- function Suite(title) {
3146
+ function Suite(title, ctx) {
2743
3147
  this.title = title;
3148
+ this.ctx = ctx;
2744
3149
  this.suites = [];
2745
3150
  this.tests = [];
2746
3151
  this._beforeEach = [];
@@ -2770,6 +3175,7 @@ Suite.prototype.constructor = Suite;
2770
3175
  Suite.prototype.clone = function(){
2771
3176
  var suite = new Suite(this.title);
2772
3177
  debug('clone');
3178
+ suite.ctx = this.ctx;
2773
3179
  suite.timeout(this.timeout());
2774
3180
  suite.bail(this.bail());
2775
3181
  return suite;
@@ -2818,6 +3224,7 @@ Suite.prototype.beforeAll = function(fn){
2818
3224
  var hook = new Hook('"before all" hook', fn);
2819
3225
  hook.parent = this;
2820
3226
  hook.timeout(this.timeout());
3227
+ hook.ctx = this.ctx;
2821
3228
  this._beforeAll.push(hook);
2822
3229
  this.emit('beforeAll', hook);
2823
3230
  return this;
@@ -2835,6 +3242,7 @@ Suite.prototype.afterAll = function(fn){
2835
3242
  var hook = new Hook('"after all" hook', fn);
2836
3243
  hook.parent = this;
2837
3244
  hook.timeout(this.timeout());
3245
+ hook.ctx = this.ctx;
2838
3246
  this._afterAll.push(hook);
2839
3247
  this.emit('afterAll', hook);
2840
3248
  return this;
@@ -2852,6 +3260,7 @@ Suite.prototype.beforeEach = function(fn){
2852
3260
  var hook = new Hook('"before each" hook', fn);
2853
3261
  hook.parent = this;
2854
3262
  hook.timeout(this.timeout());
3263
+ hook.ctx = this.ctx;
2855
3264
  this._beforeEach.push(hook);
2856
3265
  this.emit('beforeEach', hook);
2857
3266
  return this;
@@ -2869,6 +3278,7 @@ Suite.prototype.afterEach = function(fn){
2869
3278
  var hook = new Hook('"after each" hook', fn);
2870
3279
  hook.parent = this;
2871
3280
  hook.timeout(this.timeout());
3281
+ hook.ctx = this.ctx;
2872
3282
  this._afterEach.push(hook);
2873
3283
  this.emit('afterEach', hook);
2874
3284
  return this;
@@ -2902,6 +3312,7 @@ Suite.prototype.addSuite = function(suite){
2902
3312
  Suite.prototype.addTest = function(test){
2903
3313
  test.parent = this;
2904
3314
  test.timeout(this.timeout());
3315
+ test.ctx = this.ctx;
2905
3316
  this.tests.push(test);
2906
3317
  this.emit('test', test);
2907
3318
  return this;
@@ -2974,6 +3385,22 @@ Test.prototype = new Runnable;
2974
3385
  Test.prototype.constructor = Test;
2975
3386
 
2976
3387
 
3388
+ /**
3389
+ * Inspect the context void of private properties.
3390
+ *
3391
+ * @return {String}
3392
+ * @api private
3393
+ */
3394
+
3395
+ Test.prototype.inspect = function(){
3396
+ return JSON.stringify(this, function(key, val){
3397
+ return '_' == key[0]
3398
+ ? undefined
3399
+ : 'parent' == key
3400
+ ? '#<Suite>'
3401
+ : val;
3402
+ }, 2);
3403
+ };
2977
3404
  }); // module: test.js
2978
3405
 
2979
3406
  require.register("utils.js", function(module, exports, require){
@@ -3093,9 +3520,9 @@ exports.keys = Object.keys || function(obj) {
3093
3520
  var keys = []
3094
3521
  , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
3095
3522
 
3096
- for (var i in obj) {
3097
- if (has.call(obj, i)) {
3098
- keys.push(i);
3523
+ for (var key in obj) {
3524
+ if (has.call(obj, key)) {
3525
+ keys.push(key);
3099
3526
  }
3100
3527
  }
3101
3528
 
@@ -3133,7 +3560,7 @@ function ignored(path){
3133
3560
  * Lookup files in the given `dir`.
3134
3561
  *
3135
3562
  * @return {Array}
3136
- * @api public
3563
+ * @api private
3137
3564
  */
3138
3565
 
3139
3566
  exports.files = function(dir, ret){
@@ -3223,9 +3650,8 @@ window.mocha = require('mocha');
3223
3650
 
3224
3651
  // boot
3225
3652
  ;(function(){
3226
- var suite = new mocha.Suite
3653
+ var suite = new mocha.Suite('', new mocha.Context)
3227
3654
  , utils = mocha.utils
3228
- , Reporter = mocha.reporters.HTML
3229
3655
 
3230
3656
  /**
3231
3657
  * Highlight the given string of `js`.
@@ -3236,13 +3662,24 @@ window.mocha = require('mocha');
3236
3662
  .replace(/</g, '&lt;')
3237
3663
  .replace(/>/g, '&gt;')
3238
3664
  .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
3239
- .replace(/('.*')/gm, '<span class="string">$1</span>')
3665
+ .replace(/('.*?')/gm, '<span class="string">$1</span>')
3240
3666
  .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
3241
3667
  .replace(/(\d+)/gm, '<span class="number">$1</span>')
3242
3668
  .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
3243
3669
  .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
3244
3670
  }
3245
3671
 
3672
+ /**
3673
+ * Highlight code contents.
3674
+ */
3675
+
3676
+ function highlightCode() {
3677
+ var code = document.getElementsByTagName('code');
3678
+ for (var i = 0, len = code.length; i < len; ++i) {
3679
+ code[i].innerHTML = highlight(code[i].innerHTML);
3680
+ }
3681
+ }
3682
+
3246
3683
  /**
3247
3684
  * Parse the given `qs`.
3248
3685
  */
@@ -3273,17 +3710,14 @@ window.mocha = require('mocha');
3273
3710
  * Run mocha, returning the Runner.
3274
3711
  */
3275
3712
 
3276
- mocha.run = function(){
3713
+ mocha.run = function(Reporter){
3277
3714
  suite.emit('run');
3278
3715
  var runner = new mocha.Runner(suite);
3716
+ Reporter = Reporter || mocha.reporters.HTML;
3279
3717
  var reporter = new Reporter(runner);
3280
3718
  var query = parse(window.location.search || "");
3281
3719
  if (query.grep) runner.grep(new RegExp(query.grep));
3282
- runner.on('end', function(){
3283
- $('code').each(function(){
3284
- $(this).html(highlight($(this).text()));
3285
- });
3286
- });
3720
+ runner.on('end', highlightCode);
3287
3721
  return runner.run();
3288
3722
  };
3289
3723
  })();