Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added beginnings of test runner - still need Rei.initialize() to take…

… a callback
  • Loading branch information...
commit 9a2a6856beeb2f9954a0a32ac8aacc62a24b0832 1 parent aa95fc8
Yoz Grahame yozlet authored committed
37 app/test.html
... ... @@ -0,0 +1,37 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 + <head>
  4 + <title>Rei Tests</title>
  5 + <!-- Test framework -->
  6 + <script src="tests/mocha.js"></script>
  7 + <script src="tests/chai.js"></script>
  8 + <script>mocha.setup('bdd')</script>
  9 +
  10 + <script src="scripts/require-jquery.js"></script>
  11 + <script src="tests/test.dummy.js"></script>
  12 + <script>
  13 + $(function(){
  14 + requirejs.config({
  15 + baseUrl: 'scripts'
  16 + });
  17 + requirejs(['./rei'], function(rei) {
  18 + window.Rei = rei;
  19 + var runner = mocha.run();
  20 + runner.globals(['PLUGINS', 'jQuery', 'chai', 'Rei', 'word']);
  21 +
  22 + runner.on('test end', function(test){
  23 + console.log(test.fullTitle());
  24 + });
  25 + });
  26 + });
  27 + </script>
  28 +
  29 +
  30 + <link rel="stylesheet" type="text/css" href="tests/mocha.css"/>
  31 +
  32 + </head>
  33 + <body>
  34 + <div id="mocha"></div>
  35 + </div>
  36 + </body>
  37 +</html>
3,473 app/tests/chai.js
3,473 additions, 0 deletions not shown
199 app/tests/mocha.css
... ... @@ -0,0 +1,199 @@
  1 +@charset "UTF-8";
  2 +body {
  3 + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
  4 + padding: 60px 50px;
  5 +}
  6 +
  7 +#mocha ul, #mocha li {
  8 + margin: 0;
  9 + padding: 0;
  10 +}
  11 +
  12 +#mocha ul {
  13 + list-style: none;
  14 +}
  15 +
  16 +#mocha h1, #mocha h2 {
  17 + margin: 0;
  18 +}
  19 +
  20 +#mocha h1 {
  21 + margin-top: 15px;
  22 + font-size: 1em;
  23 + font-weight: 200;
  24 +}
  25 +
  26 +#mocha h1 a {
  27 + text-decoration: none;
  28 + color: inherit;
  29 +}
  30 +
  31 +#mocha h1 a:hover {
  32 + text-decoration: underline;
  33 +}
  34 +
  35 +#mocha .suite .suite h1 {
  36 + margin-top: 0;
  37 + font-size: .8em;
  38 +}
  39 +
  40 +#mocha h2 {
  41 + font-size: 12px;
  42 + font-weight: normal;
  43 + cursor: pointer;
  44 +}
  45 +
  46 +#mocha .suite {
  47 + margin-left: 15px;
  48 +}
  49 +
  50 +#mocha .test {
  51 + margin-left: 15px;
  52 +}
  53 +
  54 +#mocha .test:hover h2::after {
  55 + position: relative;
  56 + top: 0;
  57 + right: -10px;
  58 + content: '(view source)';
  59 + font-size: 12px;
  60 + font-family: arial;
  61 + color: #888;
  62 +}
  63 +
  64 +#mocha .test.pending:hover h2::after {
  65 + content: '(pending)';
  66 + font-family: arial;
  67 +}
  68 +
  69 +#mocha .test.pass.medium .duration {
  70 + background: #C09853;
  71 +}
  72 +
  73 +#mocha .test.pass.slow .duration {
  74 + background: #B94A48;
  75 +}
  76 +
  77 +#mocha .test.pass::before {
  78 + content: '✓';
  79 + font-size: 12px;
  80 + display: block;
  81 + float: left;
  82 + margin-right: 5px;
  83 + color: #00d6b2;
  84 +}
  85 +
  86 +#mocha .test.pass .duration {
  87 + font-size: 9px;
  88 + margin-left: 5px;
  89 + padding: 2px 5px;
  90 + color: white;
  91 + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
  92 + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
  93 + box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
  94 + -webkit-border-radius: 5px;
  95 + -moz-border-radius: 5px;
  96 + -ms-border-radius: 5px;
  97 + -o-border-radius: 5px;
  98 + border-radius: 5px;
  99 +}
  100 +
  101 +#mocha .test.pass.fast .duration {
  102 + display: none;
  103 +}
  104 +
  105 +#mocha .test.pending {
  106 + color: #0b97c4;
  107 +}
  108 +
  109 +#mocha .test.pending::before {
  110 + content: '◦';
  111 + color: #0b97c4;
  112 +}
  113 +
  114 +#mocha .test.fail {
  115 + color: #c00;
  116 +}
  117 +
  118 +#mocha .test.fail pre {
  119 + color: black;
  120 +}
  121 +
  122 +#mocha .test.fail::before {
  123 + content: '✖';
  124 + font-size: 12px;
  125 + display: block;
  126 + float: left;
  127 + margin-right: 5px;
  128 + color: #c00;
  129 +}
  130 +
  131 +#mocha .test pre.error {
  132 + color: #c00;
  133 +}
  134 +
  135 +#mocha .test pre {
  136 + display: inline-block;
  137 + font: 12px/1.5 monaco, monospace;
  138 + margin: 5px;
  139 + padding: 15px;
  140 + border: 1px solid #eee;
  141 + border-bottom-color: #ddd;
  142 + -webkit-border-radius: 3px;
  143 + -webkit-box-shadow: 0 1px 3px #eee;
  144 +}
  145 +
  146 +#report.pass .test.fail {
  147 + display: none;
  148 +}
  149 +
  150 +#report.fail .test.pass {
  151 + display: none;
  152 +}
  153 +
  154 +#error {
  155 + color: #c00;
  156 + font-size: 1.5 em;
  157 + font-weight: 100;
  158 + letter-spacing: 1px;
  159 +}
  160 +
  161 +#stats {
  162 + position: fixed;
  163 + top: 15px;
  164 + right: 10px;
  165 + font-size: 12px;
  166 + margin: 0;
  167 + color: #888;
  168 +}
  169 +
  170 +#stats .progress {
  171 + float: right;
  172 + padding-top: 0;
  173 +}
  174 +
  175 +#stats em {
  176 + color: black;
  177 +}
  178 +
  179 +#stats a {
  180 + text-decoration: none;
  181 + color: inherit;
  182 +}
  183 +
  184 +#stats a:hover {
  185 + border-bottom: 1px solid #eee;
  186 +}
  187 +
  188 +#stats li {
  189 + display: inline-block;
  190 + margin: 0 5px;
  191 + list-style: none;
  192 + padding-top: 11px;
  193 +}
  194 +
  195 +code .comment { color: #ddd }
  196 +code .init { color: #2F6FAD }
  197 +code .string { color: #5890AD }
  198 +code .keyword { color: #8A6343 }
  199 +code .number { color: #2F6FAD }
4,579 app/tests/mocha.js
... ... @@ -0,0 +1,4579 @@
  1 +;(function(){
  2 +
  3 +
  4 +// CommonJS require()
  5 +
  6 +function require(p){
  7 + var path = require.resolve(p)
  8 + , mod = require.modules[path];
  9 + if (!mod) throw new Error('failed to require "' + p + '"');
  10 + if (!mod.exports) {
  11 + mod.exports = {};
  12 + mod.call(mod.exports, mod, mod.exports, require.relative(path));
  13 + }
  14 + return mod.exports;
  15 + }
  16 +
  17 +require.modules = {};
  18 +
  19 +require.resolve = function (path){
  20 + var orig = path
  21 + , reg = path + '.js'
  22 + , index = path + '/index.js';
  23 + return require.modules[reg] && reg
  24 + || require.modules[index] && index
  25 + || orig;
  26 + };
  27 +
  28 +require.register = function (path, fn){
  29 + require.modules[path] = fn;
  30 + };
  31 +
  32 +require.relative = function (parent) {
  33 + return function(p){
  34 + if ('.' != p.charAt(0)) return require(p);
  35 +
  36 + var path = parent.split('/')
  37 + , segs = p.split('/');
  38 + path.pop();
  39 +
  40 + for (var i = 0; i < segs.length; i++) {
  41 + var seg = segs[i];
  42 + if ('..' == seg) path.pop();
  43 + else if ('.' != seg) path.push(seg);
  44 + }
  45 +
  46 + return require(path.join('/'));
  47 + };
  48 + };
  49 +
  50 +
  51 +require.register("browser/debug.js", function(module, exports, require){
  52 +
  53 +module.exports = function(type){
  54 + return function(){
  55 +
  56 + }
  57 +};
  58 +}); // module: browser/debug.js
  59 +
  60 +require.register("browser/diff.js", function(module, exports, require){
  61 +
  62 +}); // module: browser/diff.js
  63 +
  64 +require.register("browser/events.js", function(module, exports, require){
  65 +
  66 +/**
  67 + * Module exports.
  68 + */
  69 +
  70 +exports.EventEmitter = EventEmitter;
  71 +
  72 +/**
  73 + * Check if `obj` is an array.
  74 + */
  75 +
  76 +function isArray(obj) {
  77 + return '[object Array]' == {}.toString.call(obj);
  78 +}
  79 +
  80 +/**
  81 + * Event emitter constructor.
  82 + *
  83 + * @api public
  84 + */
  85 +
  86 +function EventEmitter(){};
  87 +
  88 +/**
  89 + * Adds a listener.
  90 + *
  91 + * @api public
  92 + */
  93 +
  94 +EventEmitter.prototype.on = function (name, fn) {
  95 + if (!this.$events) {
  96 + this.$events = {};
  97 + }
  98 +
  99 + if (!this.$events[name]) {
  100 + this.$events[name] = fn;
  101 + } else if (isArray(this.$events[name])) {
  102 + this.$events[name].push(fn);
  103 + } else {
  104 + this.$events[name] = [this.$events[name], fn];
  105 + }
  106 +
  107 + return this;
  108 +};
  109 +
  110 +EventEmitter.prototype.addListener = EventEmitter.prototype.on;
  111 +
  112 +/**
  113 + * Adds a volatile listener.
  114 + *
  115 + * @api public
  116 + */
  117 +
  118 +EventEmitter.prototype.once = function (name, fn) {
  119 + var self = this;
  120 +
  121 + function on () {
  122 + self.removeListener(name, on);
  123 + fn.apply(this, arguments);
  124 + };
  125 +
  126 + on.listener = fn;
  127 + this.on(name, on);
  128 +
  129 + return this;
  130 +};
  131 +
  132 +/**
  133 + * Removes a listener.
  134 + *
  135 + * @api public
  136 + */
  137 +
  138 +EventEmitter.prototype.removeListener = function (name, fn) {
  139 + if (this.$events && this.$events[name]) {
  140 + var list = this.$events[name];
  141 +
  142 + if (isArray(list)) {
  143 + var pos = -1;
  144 +
  145 + for (var i = 0, l = list.length; i < l; i++) {
  146 + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
  147 + pos = i;
  148 + break;
  149 + }
  150 + }
  151 +
  152 + if (pos < 0) {
  153 + return this;
  154 + }
  155 +
  156 + list.splice(pos, 1);
  157 +
  158 + if (!list.length) {
  159 + delete this.$events[name];
  160 + }
  161 + } else if (list === fn || (list.listener && list.listener === fn)) {
  162 + delete this.$events[name];
  163 + }
  164 + }
  165 +
  166 + return this;
  167 +};
  168 +
  169 +/**
  170 + * Removes all listeners for an event.
  171 + *
  172 + * @api public
  173 + */
  174 +
  175 +EventEmitter.prototype.removeAllListeners = function (name) {
  176 + if (name === undefined) {
  177 + this.$events = {};
  178 + return this;
  179 + }
  180 +
  181 + if (this.$events && this.$events[name]) {
  182 + this.$events[name] = null;
  183 + }
  184 +
  185 + return this;
  186 +};
  187 +
  188 +/**
  189 + * Gets all listeners for a certain event.
  190 + *
  191 + * @api public
  192 + */
  193 +
  194 +EventEmitter.prototype.listeners = function (name) {
  195 + if (!this.$events) {
  196 + this.$events = {};
  197 + }
  198 +
  199 + if (!this.$events[name]) {
  200 + this.$events[name] = [];
  201 + }
  202 +
  203 + if (!isArray(this.$events[name])) {
  204 + this.$events[name] = [this.$events[name]];
  205 + }
  206 +
  207 + return this.$events[name];
  208 +};
  209 +
  210 +/**
  211 + * Emits an event.
  212 + *
  213 + * @api public
  214 + */
  215 +
  216 +EventEmitter.prototype.emit = function (name) {
  217 + if (!this.$events) {
  218 + return false;
  219 + }
  220 +
  221 + var handler = this.$events[name];
  222 +
  223 + if (!handler) {
  224 + return false;
  225 + }
  226 +
  227 + var args = [].slice.call(arguments, 1);
  228 +
  229 + if ('function' == typeof handler) {
  230 + handler.apply(this, args);
  231 + } else if (isArray(handler)) {
  232 + var listeners = handler.slice();
  233 +
  234 + for (var i = 0, l = listeners.length; i < l; i++) {
  235 + listeners[i].apply(this, args);
  236 + }
  237 + } else {
  238 + return false;
  239 + }
  240 +
  241 + return true;
  242 +};
  243 +}); // module: browser/events.js
  244 +
  245 +require.register("browser/fs.js", function(module, exports, require){
  246 +
  247 +}); // module: browser/fs.js
  248 +
  249 +require.register("browser/path.js", function(module, exports, require){
  250 +
  251 +}); // module: browser/path.js
  252 +
  253 +require.register("browser/progress.js", function(module, exports, require){
  254 +
  255 +/**
  256 + * Expose `Progress`.
  257 + */
  258 +
  259 +module.exports = Progress;
  260 +
  261 +/**
  262 + * Initialize a new `Progress` indicator.
  263 + */
  264 +
  265 +function Progress() {
  266 + this.percent = 0;
  267 + this.size(0);
  268 + this.fontSize(11);
  269 + this.font('helvetica, arial, sans-serif');
  270 +}
  271 +
  272 +/**
  273 + * Set progress size to `n`.
  274 + *
  275 + * @param {Number} n
  276 + * @return {Progress} for chaining
  277 + * @api public
  278 + */
  279 +
  280 +Progress.prototype.size = function(n){
  281 + this._size = n;
  282 + return this;
  283 +};
  284 +
  285 +/**
  286 + * Set text to `str`.
  287 + *
  288 + * @param {String} str
  289 + * @return {Progress} for chaining
  290 + * @api public
  291 + */
  292 +
  293 +Progress.prototype.text = function(str){
  294 + this._text = str;
  295 + return this;
  296 +};
  297 +
  298 +/**
  299 + * Set font size to `n`.
  300 + *
  301 + * @param {Number} n
  302 + * @return {Progress} for chaining
  303 + * @api public
  304 + */
  305 +
  306 +Progress.prototype.fontSize = function(n){
  307 + this._fontSize = n;
  308 + return this;
  309 +};
  310 +
  311 +/**
  312 + * Set font `family`.
  313 + *
  314 + * @param {String} family
  315 + * @return {Progress} for chaining
  316 + */
  317 +
  318 +Progress.prototype.font = function(family){
  319 + this._font = family;
  320 + return this;
  321 +};
  322 +
  323 +/**
  324 + * Update percentage to `n`.
  325 + *
  326 + * @param {Number} n
  327 + * @return {Progress} for chaining
  328 + */
  329 +
  330 +Progress.prototype.update = function(n){
  331 + this.percent = n;
  332 + return this;
  333 +};
  334 +
  335 +/**
  336 + * Draw on `ctx`.
  337 + *
  338 + * @param {CanvasRenderingContext2d} ctx
  339 + * @return {Progress} for chaining
  340 + */
  341 +
  342 +Progress.prototype.draw = function(ctx){
  343 + var percent = Math.min(this.percent, 100)
  344 + , size = this._size
  345 + , half = size / 2
  346 + , x = half
  347 + , y = half
  348 + , rad = half - 1
  349 + , fontSize = this._fontSize;
  350 +
  351 + ctx.font = fontSize + 'px ' + this._font;
  352 +
  353 + var angle = Math.PI * 2 * (percent / 100);
  354 + ctx.clearRect(0, 0, size, size);
  355 +
  356 + // outer circle
  357 + ctx.strokeStyle = '#9f9f9f';
  358 + ctx.beginPath();
  359 + ctx.arc(x, y, rad, 0, angle, false);
  360 + ctx.stroke();
  361 +
  362 + // inner circle
  363 + ctx.strokeStyle = '#eee';
  364 + ctx.beginPath();
  365 + ctx.arc(x, y, rad - 1, 0, angle, true);
  366 + ctx.stroke();
  367 +
  368 + // text
  369 + var text = this._text || (percent | 0) + '%'
  370 + , w = ctx.measureText(text).width;
  371 +
  372 + ctx.fillText(
  373 + text
  374 + , x - w / 2 + 1
  375 + , y + fontSize / 2 - 1);
  376 +
  377 + return this;
  378 +};
  379 +
  380 +}); // module: browser/progress.js
  381 +
  382 +require.register("browser/tty.js", function(module, exports, require){
  383 +
  384 +exports.isatty = function(){
  385 + return true;
  386 +};
  387 +
  388 +exports.getWindowSize = function(){
  389 + return [window.innerHeight, window.innerWidth];
  390 +};
  391 +}); // module: browser/tty.js
  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 or get the context `Runnable` to `runnable`.
  411 + *
  412 + * @param {Runnable} runnable
  413 + * @return {Context}
  414 + * @api private
  415 + */
  416 +
  417 +Context.prototype.runnable = function(runnable){
  418 + if (0 == arguments.length) return this._runnable;
  419 + this.test = this._runnable = runnable;
  420 + return this;
  421 +};
  422 +
  423 +/**
  424 + * Set test timeout `ms`.
  425 + *
  426 + * @param {Number} ms
  427 + * @return {Context} self
  428 + * @api private
  429 + */
  430 +
  431 +Context.prototype.timeout = function(ms){
  432 + this.runnable().timeout(ms);
  433 + return this;
  434 +};
  435 +
  436 +/**
  437 + * Inspect the context void of `._runnable`.
  438 + *
  439 + * @return {String}
  440 + * @api private
  441 + */
  442 +
  443 +Context.prototype.inspect = function(){
  444 + return JSON.stringify(this, function(key, val){
  445 + if ('_runnable' == key) return;
  446 + if ('test' == key) return;
  447 + return val;
  448 + }, 2);
  449 +};
  450 +
  451 +}); // module: context.js
  452 +
  453 +require.register("hook.js", function(module, exports, require){
  454 +
  455 +/**
  456 + * Module dependencies.
  457 + */
  458 +
  459 +var Runnable = require('./runnable');
  460 +
  461 +/**
  462 + * Expose `Hook`.
  463 + */
  464 +
  465 +module.exports = Hook;
  466 +
  467 +/**
  468 + * Initialize a new `Hook` with the given `title` and callback `fn`.
  469 + *
  470 + * @param {String} title
  471 + * @param {Function} fn
  472 + * @api private
  473 + */
  474 +
  475 +function Hook(title, fn) {
  476 + Runnable.call(this, title, fn);
  477 + this.type = 'hook';
  478 +}
  479 +
  480 +/**
  481 + * Inherit from `Runnable.prototype`.
  482 + */
  483 +
  484 +Hook.prototype = new Runnable;
  485 +Hook.prototype.constructor = Hook;
  486 +
  487 +
  488 +/**
  489 + * Get or set the test `err`.
  490 + *
  491 + * @param {Error} err
  492 + * @return {Error}
  493 + * @api public
  494 + */
  495 +
  496 +Hook.prototype.error = function(err){
  497 + if (0 == arguments.length) {
  498 + var err = this._error;
  499 + this._error = null;
  500 + return err;
  501 + }
  502 +
  503 + this._error = err;
  504 +};
  505 +
  506 +
  507 +}); // module: hook.js
  508 +
  509 +require.register("interfaces/bdd.js", function(module, exports, require){
  510 +
  511 +/**
  512 + * Module dependencies.
  513 + */
  514 +
  515 +var Suite = require('../suite')
  516 + , Test = require('../test');
  517 +
  518 +/**
  519 + * BDD-style interface:
  520 + *
  521 + * describe('Array', function(){
  522 + * describe('#indexOf()', function(){
  523 + * it('should return -1 when not present', function(){
  524 + *
  525 + * });
  526 + *
  527 + * it('should return the index when present', function(){
  528 + *
  529 + * });
  530 + * });
  531 + * });
  532 + *
  533 + */
  534 +
  535 +module.exports = function(suite){
  536 + var suites = [suite];
  537 +
  538 + suite.on('pre-require', function(context){
  539 +
  540 + // pending variants
  541 +
  542 + context.xdescribe = function(title, fn){
  543 + var suite = Suite.create(suites[0], title);
  544 + suite.pending = true;
  545 + suites.unshift(suite);
  546 + fn();
  547 + suites.shift();
  548 + };
  549 + context.xit = function(title){
  550 + context.it(title);
  551 + };
  552 +
  553 + /**
  554 + * Execute before running tests.
  555 + */
  556 +
  557 + context.before = function(fn){
  558 + suites[0].beforeAll(fn);
  559 + };
  560 +
  561 + /**
  562 + * Execute after running tests.
  563 + */
  564 +
  565 + context.after = function(fn){
  566 + suites[0].afterAll(fn);
  567 + };
  568 +
  569 + /**
  570 + * Execute before each test case.
  571 + */
  572 +
  573 + context.beforeEach = function(fn){
  574 + suites[0].beforeEach(fn);
  575 + };
  576 +
  577 + /**
  578 + * Execute after each test case.
  579 + */
  580 +
  581 + context.afterEach = function(fn){
  582 + suites[0].afterEach(fn);
  583 + };
  584 +
  585 + /**
  586 + * Describe a "suite" with the given `title`
  587 + * and callback `fn` containing nested suites
  588 + * and/or tests.
  589 + */
  590 +
  591 + context.describe = context.context = function(title, fn){
  592 + var suite = Suite.create(suites[0], title);
  593 + suites.unshift(suite);
  594 + fn();
  595 + suites.shift();
  596 + };
  597 +
  598 + /**
  599 + * Describe a specification or test-case
  600 + * with the given `title` and callback `fn`
  601 + * acting as a thunk.
  602 + */
  603 +
  604 + context.it = context.specify = function(title, fn){
  605 + if (suites[0].pending) var fn = undefined;
  606 + suites[0].addTest(new Test(title, fn));
  607 + };
  608 + });
  609 +};
  610 +
  611 +}); // module: interfaces/bdd.js
  612 +
  613 +require.register("interfaces/exports.js", function(module, exports, require){
  614 +
  615 +/**
  616 + * Module dependencies.
  617 + */
  618 +
  619 +var Suite = require('../suite')
  620 + , Test = require('../test');
  621 +
  622 +/**
  623 + * TDD-style interface:
  624 + *
  625 + * exports.Array = {
  626 + * '#indexOf()': {
  627 + * 'should return -1 when the value is not present': function(){
  628 + *
  629 + * },
  630 + *
  631 + * 'should return the correct index when the value is present': function(){
  632 + *
  633 + * }
  634 + * }
  635 + * };
  636 + *
  637 + */
  638 +
  639 +module.exports = function(suite){
  640 + var suites = [suite];
  641 +
  642 + suite.on('require', visit);
  643 +
  644 + function visit(obj) {
  645 + var suite;
  646 + for (var key in obj) {
  647 + if ('function' == typeof obj[key]) {
  648 + var fn = obj[key];
  649 + switch (key) {
  650 + case 'before':
  651 + suites[0].beforeAll(fn);
  652 + break;
  653 + case 'after':
  654 + suites[0].afterAll(fn);
  655 + break;
  656 + case 'beforeEach':
  657 + suites[0].beforeEach(fn);
  658 + break;
  659 + case 'afterEach':
  660 + suites[0].afterEach(fn);
  661 + break;
  662 + default:
  663 + suites[0].addTest(new Test(key, fn));
  664 + }
  665 + } else {
  666 + var suite = Suite.create(suites[0], key);
  667 + suites.unshift(suite);
  668 + visit(obj[key]);
  669 + suites.shift();
  670 + }
  671 + }
  672 + }
  673 +};
  674 +}); // module: interfaces/exports.js
  675 +
  676 +require.register("interfaces/index.js", function(module, exports, require){
  677 +
  678 +exports.bdd = require('./bdd');
  679 +exports.tdd = require('./tdd');
  680 +exports.qunit = require('./qunit');
  681 +exports.exports = require('./exports');
  682 +
  683 +}); // module: interfaces/index.js
  684 +
  685 +require.register("interfaces/qunit.js", function(module, exports, require){
  686 +
  687 +/**
  688 + * Module dependencies.
  689 + */
  690 +
  691 +var Suite = require('../suite')
  692 + , Test = require('../test');
  693 +
  694 +/**
  695 + * QUnit-style interface:
  696 + *
  697 + * suite('Array');
  698 + *
  699 + * test('#length', function(){
  700 + * var arr = [1,2,3];
  701 + * ok(arr.length == 3);
  702 + * });
  703 + *
  704 + * test('#indexOf()', function(){
  705 + * var arr = [1,2,3];
  706 + * ok(arr.indexOf(1) == 0);
  707 + * ok(arr.indexOf(2) == 1);
  708 + * ok(arr.indexOf(3) == 2);
  709 + * });
  710 + *
  711 + * suite('String');
  712 + *
  713 + * test('#length', function(){
  714 + * ok('foo'.length == 3);
  715 + * });
  716 + *
  717 + */
  718 +
  719 +module.exports = function(suite){
  720 + var suites = [suite];
  721 +
  722 + suite.on('pre-require', function(context){
  723 +
  724 + /**
  725 + * Execute before running tests.
  726 + */
  727 +
  728 + context.before = function(fn){
  729 + suites[0].beforeAll(fn);
  730 + };
  731 +
  732 + /**
  733 + * Execute after running tests.
  734 + */
  735 +
  736 + context.after = function(fn){
  737 + suites[0].afterAll(fn);
  738 + };
  739 +
  740 + /**
  741 + * Execute before each test case.
  742 + */
  743 +
  744 + context.beforeEach = function(fn){
  745 + suites[0].beforeEach(fn);
  746 + };
  747 +
  748 + /**
  749 + * Execute after each test case.
  750 + */
  751 +
  752 + context.afterEach = function(fn){
  753 + suites[0].afterEach(fn);
  754 + };
  755 +
  756 + /**
  757 + * Describe a "suite" with the given `title`.
  758 + */
  759 +
  760 + context.suite = function(title){
  761 + if (suites.length > 1) suites.shift();
  762 + var suite = Suite.create(suites[0], title);
  763 + suites.unshift(suite);
  764 + };
  765 +
  766 + /**
  767 + * Describe a specification or test-case
  768 + * with the given `title` and callback `fn`
  769 + * acting as a thunk.
  770 + */
  771 +
  772 + context.test = function(title, fn){
  773 + suites[0].addTest(new Test(title, fn));
  774 + };
  775 + });
  776 +};
  777 +
  778 +}); // module: interfaces/qunit.js
  779 +
  780 +require.register("interfaces/tdd.js", function(module, exports, require){
  781 +
  782 +/**
  783 + * Module dependencies.
  784 + */
  785 +
  786 +var Suite = require('../suite')
  787 + , Test = require('../test');
  788 +
  789 +/**
  790 + * TDD-style interface:
  791 + *
  792 + * suite('Array', function(){
  793 + * suite('#indexOf()', function(){
  794 + * suiteSetup(function(){
  795 + *
  796 + * });
  797 + *
  798 + * test('should return -1 when not present', function(){
  799 + *
  800 + * });
  801 + *
  802 + * test('should return the index when present', function(){
  803 + *
  804 + * });
  805 + *
  806 + * suiteTeardown(function(){
  807 + *
  808 + * });
  809 + * });
  810 + * });
  811 + *
  812 + */
  813 +
  814 +module.exports = function(suite){
  815 + var suites = [suite];
  816 +
  817 + suite.on('pre-require', function(context){
  818 +
  819 + /**
  820 + * Execute before each test case.
  821 + */
  822 +
  823 + context.setup = function(fn){
  824 + suites[0].beforeEach(fn);
  825 + };
  826 +
  827 + /**
  828 + * Execute after each test case.
  829 + */
  830 +
  831 + context.teardown = function(fn){
  832 + suites[0].afterEach(fn);
  833 + };
  834 +
  835 + /**
  836 + * Execute before the suite.
  837 + */
  838 +
  839 + context.suiteSetup = function(fn){
  840 + suites[0].beforeAll(fn);
  841 + };
  842 +
  843 + /**
  844 + * Execute after the suite.
  845 + */
  846 +
  847 + context.suiteTeardown = function(fn){
  848 + suites[0].afterAll(fn);
  849 + };
  850 +
  851 + /**
  852 + * Describe a "suite" with the given `title`
  853 + * and callback `fn` containing nested suites
  854 + * and/or tests.
  855 + */
  856 +
  857 + context.suite = function(title, fn){
  858 + var suite = Suite.create(suites[0], title);
  859 + suites.unshift(suite);
  860 + fn();
  861 + suites.shift();
  862 + };
  863 +
  864 + /**
  865 + * Describe a specification or test-case
  866 + * with the given `title` and callback `fn`
  867 + * acting as a thunk.
  868 + */
  869 +
  870 + context.test = function(title, fn){
  871 + suites[0].addTest(new Test(title, fn));
  872 + };
  873 + });
  874 +};
  875 +
  876 +}); // module: interfaces/tdd.js
  877 +
  878 +require.register("mocha.js", function(module, exports, require){
  879 +/*!
  880 + * mocha
  881 + * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
  882 + * MIT Licensed
  883 + */
  884 +
  885 +/**
  886 + * Module dependencies.
  887 + */
  888 +
  889 +var path = require('browser/path');
  890 +
  891 +/**
  892 + * Expose `Mocha`.
  893 + */
  894 +
  895 +exports = module.exports = Mocha;
  896 +
  897 +/**
  898 + * Expose internals.
  899 + */
  900 +
  901 +exports.utils = require('./utils');
  902 +exports.interfaces = require('./interfaces');
  903 +exports.reporters = require('./reporters');
  904 +exports.Runnable = require('./runnable');
  905 +exports.Context = require('./context');
  906 +exports.Runner = require('./runner');
  907 +exports.Suite = require('./suite');
  908 +exports.Hook = require('./hook');
  909 +exports.Test = require('./test');
  910 +
  911 +/**
  912 + * Return image `name` path.
  913 + *
  914 + * @param {String} name
  915 + * @return {String}
  916 + * @api private
  917 + */
  918 +
  919 +function image(name) {
  920 + return __dirname + '/../images/' + name + '.png';
  921 +}
  922 +
  923 +/**
  924 + * Setup mocha with `options`.
  925 + *
  926 + * Options:
  927 + *
  928 + * - `ui` name "bdd", "tdd", "exports" etc
  929 + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
  930 + * - `globals` array of accepted globals
  931 + * - `timeout` timeout in milliseconds
  932 + * - `ignoreLeaks` ignore global leaks
  933 + * - `grep` string or regexp to filter tests with
  934 + *
  935 + * @param {Object} options
  936 + * @api public
  937 + */
  938 +
  939 +function Mocha(options) {
  940 + options = options || {};
  941 + this.files = [];
  942 + this.options = options;
  943 + this.grep(options.grep);
  944 + this.suite = new exports.Suite('', new exports.Context);
  945 + this.ui(options.ui);
  946 + this.reporter(options.reporter);
  947 + if (options.timeout) this.suite.timeout(options.timeout);
  948 +}
  949 +
  950 +/**
  951 + * Add test `file`.
  952 + *
  953 + * @param {String} file
  954 + * @api public
  955 + */
  956 +
  957 +Mocha.prototype.addFile = function(file){
  958 + this.files.push(file);
  959 + return this;
  960 +};
  961 +
  962 +/**
  963 + * Set reporter to `name`, defaults to "dot".
  964 + *
  965 + * @param {String} name
  966 + * @api public
  967 + */
  968 +
  969 +Mocha.prototype.reporter = function(name){
  970 + name = name || 'dot';
  971 + this._reporter = require('./reporters/' + name);
  972 + if (!this._reporter) throw new Error('invalid reporter "' + name + '"');
  973 + return this;
  974 +};
  975 +
  976 +/**
  977 + * Set test UI `name`, defaults to "bdd".
  978 + *
  979 + * @param {String} bdd
  980 + * @api public
  981 + */
  982 +
  983 +Mocha.prototype.ui = function(name){
  984 + name = name || 'bdd';
  985 + this._ui = exports.interfaces[name];
  986 + if (!this._ui) throw new Error('invalid interface "' + name + '"');
  987 + this._ui = this._ui(this.suite);
  988 + return this;
  989 +};
  990 +
  991 +/**
  992 + * Load registered files.
  993 + *
  994 + * @api private
  995 + */
  996 +
  997 +Mocha.prototype.loadFiles = function(fn){
  998 + var suite = this.suite;
  999 + var pending = this.files.length;
  1000 + this.files.forEach(function(file){
  1001 + file = path.resolve(file);
  1002 + suite.emit('pre-require', global, file);
  1003 + suite.emit('require', require(file), file);
  1004 + suite.emit('post-require', global, file);
  1005 + --pending || (fn && fn());
  1006 + });
  1007 +};
  1008 +
  1009 +/**
  1010 + * Enable growl support.
  1011 + *
  1012 + * @api private
  1013 + */
  1014 +
  1015 +Mocha.prototype._growl = function(runner, reporter) {
  1016 + var notify = require('growl');
  1017 +
  1018 + runner.on('end', function(){