You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2013/08/01 21:59:22 UTC

[8/8] git commit: updated refs/heads/master to 9e5eb17

Fauxton: Add testing framework

Adding mocha, sinon and chai for testing.
Tests run using phantomjs


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/9e5eb17d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/9e5eb17d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/9e5eb17d

Branch: refs/heads/master
Commit: 9e5eb17df9f846cae4f27b1e83814068f8dda909
Parents: 4479b86
Author: Garren Smith <ga...@gmail.com>
Authored: Wed Jul 17 15:56:42 2013 +0200
Committer: Garren Smith <ga...@gmail.com>
Committed: Thu Aug 1 21:58:04 2013 +0200

----------------------------------------------------------------------
 LICENSE                                         |   62 +
 NOTICE                                          |   14 +-
 src/fauxton/Gruntfile.js                        |   52 +-
 src/fauxton/app/addons/logs/tests/logSpec.js    |   27 +
 src/fauxton/package.json                        |    3 +-
 src/fauxton/readme.md                           |    4 +
 src/fauxton/tasks/couchserver.js                |   15 +-
 src/fauxton/tasks/fauxton.js                    |   25 +
 src/fauxton/tasks/helper.js                     |    1 -
 src/fauxton/test/core/routeObjectSpec.js        |   91 +
 src/fauxton/test/jasmine/index.html             |   44 -
 src/fauxton/test/jasmine/spec/example.js        |   73 -
 src/fauxton/test/jasmine/vendor/MIT.LICENSE     |   20 -
 src/fauxton/test/jasmine/vendor/jasmine-html.js |  190 -
 src/fauxton/test/jasmine/vendor/jasmine.css     |  166 -
 src/fauxton/test/jasmine/vendor/jasmine.js      | 2476 --------
 .../test/jasmine/vendor/jasmine_favicon.png     |  Bin 905 -> 0 bytes
 src/fauxton/test/mocha/chai.js                  | 4330 ++++++++++++++
 src/fauxton/test/mocha/mocha.css                |  251 +
 src/fauxton/test/mocha/mocha.js                 | 5428 ++++++++++++++++++
 src/fauxton/test/mocha/sinon-chai.js            |  109 +
 src/fauxton/test/mocha/sinon.js                 | 4290 ++++++++++++++
 src/fauxton/test/mocha/testUtils.js             |   25 +
 src/fauxton/test/qunit/index.html               |   47 -
 src/fauxton/test/qunit/tests/example.js         |   54 -
 src/fauxton/test/qunit/vendor/qunit.css         |  228 -
 src/fauxton/test/qunit/vendor/qunit.js          | 1589 -----
 src/fauxton/test/runner.html                    |   17 +
 src/fauxton/test/test.config.js                 |   71 +
 src/fauxton/test/test.config.underscore         |   15 +
 30 files changed, 14799 insertions(+), 4918 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index af0a898..2426853 100644
--- a/LICENSE
+++ b/LICENSE
@@ -895,3 +895,65 @@ For the src/couch_dbupdates component
   2009-2012 (c) Benoît Chesneau <be...@e-engura.org>
 
   Apache 2 License, see above.
+For src/fauxton/test/mocha/mocha.js and src/fauxton/test/mocha/mocha.js
+
+  Copyright (c) 2011-2013 TJ Holowaychuk <tj...@vision-media.ca>
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  'Software'), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+For src/fauxton/test/mocha/chai.js
+
+  Copyright (c) 2011-2013 Jake Luer jake@alogicalparadox.com
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  'Software'), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+for src/fauxton/test/mocha/sinon-chai.js
+
+  DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+                    Version 2, December 2004
+
+ Copyright © 2012–2013 Domenic Denicola <do...@domenicdenicola.com>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. You just DO WHAT THE FUCK YOU WANT TO.
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
index 182c267..21a6039 100644
--- a/NOTICE
+++ b/NOTICE
@@ -143,5 +143,17 @@ This product also includes the following third-party components:
    Copyright 2006-2013 (c) M. Alsup
 
  * couch_dbupdates
-
+   
    Copyright 2012, Benoît Chesneau <be...@refuge.io>
+ 
+* mocha.js (https://github.com/visionmedia/mocha)
+  
+   Copyright (c) 2011-2013 TJ Holowaychuk <tj...@vision-media.ca>
+
+ * chaijs https://github.com/chaijs
+   
+   Copyright (c) 2011-2013 Jake Luer jake@alogicalparadox.com
+
+ * sinon-chai
+
+   Copyright © 2012–2013 Domenic Denicola <do...@domenicdenicola.com>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/Gruntfile.js
----------------------------------------------------------------------
diff --git a/src/fauxton/Gruntfile.js b/src/fauxton/Gruntfile.js
index 89ab731..a0c2232 100644
--- a/src/fauxton/Gruntfile.js
+++ b/src/fauxton/Gruntfile.js
@@ -127,7 +127,7 @@ module.exports = function(grunt) {
     // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md
     lint: {
       files: [
-        "build/config.js", "app/**/*.js"
+        "build/config.js", "app/**/*.js" 
       ]
     },
 
@@ -144,7 +144,7 @@ module.exports = function(grunt) {
     // override inside main.js needs to test for them so as to not accidentally
     // route.
     jshint: {
-      all: ['app/**/*.js', 'Gruntfile.js'],
+      all: ['app/**/*.js', 'Gruntfile.js', "test/core/*.js"],
       options: {
         scripturl: true,
         evil: true
@@ -226,7 +226,7 @@ module.exports = function(grunt) {
 
     watch: {
       js: { 
-        files: helper.watchFiles(['.js'], ["./app/**/*.js", '!./app/load_addons.js',"./assets/**/*.js"]),
+        files: helper.watchFiles(['.js'], ["./app/**/*.js", '!./app/load_addons.js',"./assets/**/*.js", "./test/**/*.js"]),
         tasks: ['watchRun'],
       },
       style: {
@@ -258,18 +258,6 @@ module.exports = function(grunt) {
       }
     },
 
-    // The headless QUnit testing environment is provided for "free" by Grunt.
-    // Simply point the configuration to your test directory.
-    qunit: {
-      all: ["test/qunit/*.html"]
-    },
-
-    // The headless Jasmine testing is provided by grunt-jasmine-task. Simply
-    // point the configuration to your test directory.
-    jasmine: {
-      all: ["test/jasmine/*.html"]
-    },
-
     // Copy build artifacts and library code into the distribution
     // see - http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
     copy: {
@@ -318,7 +306,19 @@ module.exports = function(grunt) {
 
     mkcouchdb: couch_config,
     rmcouchdb: couch_config,
-    couchapp: couch_config
+    couchapp: couch_config,
+
+    mochaSetup: {
+      default: {
+        files: { src: helper.watchFiles(['[Ss]pec.js'], ['./test/core/**/*[Ss]pec.js', './app/**/*[Ss]pec.js'])},
+        template: 'test/test.config.underscore',
+        config: './app/config.js'
+      }
+    },
+
+    mocha_phantomjs: {
+      all: ['test/runner.html']
+    }
 
   });
 
@@ -327,9 +327,11 @@ module.exports = function(grunt) {
     if (!!filepath.match(/.js$/)) {
       grunt.config(['jshint', 'all'], filepath);
     }
-    /*} else if (!!filepath.match(/.css$|.less$/)) {
-      grunt.task.run(['less', 'concat:index_css']);
-    }*/
+
+    console.log(filepath);
+    if (!!filepath.match(/[Ss]pec.js$/)) {
+      grunt.task.run(['mochaSetup','mocha_phantomjs']);
+    }
   });
 
   /*
@@ -361,6 +363,7 @@ module.exports = function(grunt) {
   grunt.loadNpmTasks('grunt-contrib-uglify');
   // Load CSSMin task
   grunt.loadNpmTasks('grunt-contrib-cssmin');
+  grunt.loadNpmTasks('grunt-mocha-phantomjs');
 
   /*
    * Default task
@@ -371,8 +374,9 @@ module.exports = function(grunt) {
   /*
    * Transformation tasks
    */
-  // clean out previous build artefacts, lint and unit test
-  grunt.registerTask('test', ['clean:release', 'jshint']); //qunit
+  // clean out previous build artefactsa and lint
+  grunt.registerTask('lint', ['clean', 'jshint']);
+  grunt.registerTask('test', ['lint', 'mochaSetup', 'mocha_phantomjs']);
   // Fetch dependencies (from git or local dir), lint them and make load_addons
   grunt.registerTask('dependencies', ['get_deps', 'jshint', 'gen_load_addons:default']);
   // build templates, js and css
@@ -386,12 +390,12 @@ module.exports = function(grunt) {
   // dev server
   grunt.registerTask('dev', ['debugDev', 'couchserver']);
   // build a debug release
-  grunt.registerTask('debug', ['test', 'dependencies', 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
-  grunt.registerTask('debugDev', ['test', 'dependencies', 'less', 'concat:index_css', 'template:development', 'copy:debug']);
+  grunt.registerTask('debug', ['lint', 'dependencies', 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
+  grunt.registerTask('debugDev', ['lint', 'dependencies', 'less', 'concat:index_css', 'template:development', 'copy:debug']);
 
   grunt.registerTask('watchRun', ['clean:watch', 'dependencies']);
   // build a release
-  grunt.registerTask('release', ['test' ,'dependencies', 'build', 'minify', 'copy:dist']);
+  grunt.registerTask('release', ['lint' ,'dependencies', 'build', 'minify', 'copy:dist']);
 
   /*
    * Install into CouchDB in either debug, release, or couchapp mode

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/app/addons/logs/tests/logSpec.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/logs/tests/logSpec.js b/src/fauxton/app/addons/logs/tests/logSpec.js
new file mode 100644
index 0000000..de164aa
--- /dev/null
+++ b/src/fauxton/app/addons/logs/tests/logSpec.js
@@ -0,0 +1,27 @@
+define([
+       'addons/logs/base',
+       'chai'
+], function (Log, chai) {
+  var expect = chai.expect;
+
+  describe('Logs Addon', function(){
+
+    describe('Log Model', function () {
+      var log;
+
+      beforeEach(function () {
+        log = new Log.Model({
+          log_level: 'DEBUG',
+          pid: '1234',
+          args: 'testing 123',
+          date: (new Date()).toString()
+        });
+      });
+
+      it('should have a log level', function () {
+        expect(log.logLevel()).to.equal('DEBUG');
+      });
+
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/package.json
----------------------------------------------------------------------
diff --git a/src/fauxton/package.json b/src/fauxton/package.json
index ad69f2f..fd5e3d3 100644
--- a/src/fauxton/package.json
+++ b/src/fauxton/package.json
@@ -28,7 +28,8 @@
     "url": "~0.7.9",
     "urls": "~0.0.3",
     "http-proxy": "~0.10.2",
-    "send": "~0.1.1"
+    "send": "~0.1.1",
+    "grunt-mocha-phantomjs": "~0.3.0"
   },
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/readme.md
----------------------------------------------------------------------
diff --git a/src/fauxton/readme.md b/src/fauxton/readme.md
index af31676..2ee3293 100644
--- a/src/fauxton/readme.md
+++ b/src/fauxton/readme.md
@@ -47,6 +47,10 @@ A recent of [node.js](http://nodejs.org/) and npm is required.
 
     grunt dev
 
+### Running Tests
+    There are two ways to run the tests. `grunt test` will run the tests via the commandline. It is also possible to view them via the url
+    `http://localhost:8000/testrunner` when the dev server is running. Refreshing the url will rerun the tests via phantomjs and in the browser.
+
 ### To Deploy Fauxton
 
     ./bin/grunt couchapp_deploy - to deploy to your local [Couchdb instance] (http://localhost:5984/fauxton/_design/fauxton/index.html)

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/tasks/couchserver.js
----------------------------------------------------------------------
diff --git a/src/fauxton/tasks/couchserver.js b/src/fauxton/tasks/couchserver.js
index 679fe57..562318b 100644
--- a/src/fauxton/tasks/couchserver.js
+++ b/src/fauxton/tasks/couchserver.js
@@ -42,21 +42,28 @@ module.exports = function (grunt) {
     var proxy = new httpProxy.HttpProxy(proxy_settings);
 
     http.createServer(function (req, res) {
-      var url = req.url,
+      var url = req.url.replace('app/',''),
           accept = req.headers.accept.split(','),
           filePath;
 
       if (!!url.match(/assets/)) {
         // serve any javascript or css files from here assets dir
-        filePath = path.join('./',req.url);
+        filePath = path.join('./',url);
+      } else if (!!url.match(/mocha|\/test\/core\/|test\.config/)) {
+        filePath = path.join('./test', url.replace('/test/',''));
       } else if (!!url.match(/\.css|img/)) {
-        filePath = path.join(dist_dir,req.url);
+        filePath = path.join(dist_dir,url);
       /*} else if (!!url.match(/\/js\//)) {
         // serve any javascript or files from dist debug dir
         filePath = path.join(dist_dir,req.url);*/
       } else if (!!url.match(/\.js$|\.html$/)) {
         // server js from app directory
-        filePath = path.join(app_dir,req.url.replace('/_utils/fauxton/app',''));
+        filePath = path.join(app_dir, url.replace('/_utils/fauxton/',''));
+      } else if (!!url.match(/testrunner/)) {
+        var testSetup = grunt.util.spawn({cmd: 'grunt', grunt: true, args: ['mochaSetup']}, function (error, result, code) {/* log.writeln(String(result));*/ });
+        testSetup.stdout.pipe(process.stdout);
+        testSetup.stderr.pipe(process.stderr);
+        filePath = path.join('./test/runner.html');
       } else if (url === '/' && accept[0] !== 'application/json') {
         // serve main index file from here
         filePath = path.join(dist_dir, 'index.html');

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/tasks/fauxton.js
----------------------------------------------------------------------
diff --git a/src/fauxton/tasks/fauxton.js b/src/fauxton/tasks/fauxton.js
index ac48cf3..833a86d 100644
--- a/src/fauxton/tasks/fauxton.js
+++ b/src/fauxton/tasks/fauxton.js
@@ -89,4 +89,29 @@ module.exports = function(grunt) {
     grunt.file.write(dest, tmpl({deps: deps}));
   });
 
+  grunt.registerMultiTask('mochaSetup','Generate a config.js and runner.html for tests', function(){
+    var data = this.data,
+        configInfo,
+        _ = grunt.util._,
+        configTemplateSrc = data.template,
+        testFiles = grunt.file.expand(data.files.src);
+
+    var configTemplate = _.template(grunt.file.read(configTemplateSrc));
+    // a bit of a nasty hack to read our current config.js and get the info so we can change it 
+    // for our testing setup
+    var require = {
+      config: function (args) {
+        configInfo = args;
+        configInfo.paths['chai'] = "../test/mocha/chai";
+        configInfo.paths['sinon-chai'] = "../test/mocha/sinon-chai";
+        configInfo.paths['testUtils'] = "../test/mocha/testUtils";
+        configInfo.baseUrl = '../app';
+        delete configInfo.deps;
+      }
+    };
+
+    eval(grunt.file.read(data.config) +'');
+
+    grunt.file.write('./test/test.config.js', configTemplate({configInfo: configInfo, testFiles: testFiles}));
+  });
 };

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/tasks/helper.js
----------------------------------------------------------------------
diff --git a/src/fauxton/tasks/helper.js b/src/fauxton/tasks/helper.js
index b3a9fbd..4b66e55 100644
--- a/src/fauxton/tasks/helper.js
+++ b/src/fauxton/tasks/helper.js
@@ -40,7 +40,6 @@ exports.init = function(grunt) {
         }
         return files
       }, defaults);
-
     }
   };
 };

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/test/core/routeObjectSpec.js
----------------------------------------------------------------------
diff --git a/src/fauxton/test/core/routeObjectSpec.js b/src/fauxton/test/core/routeObjectSpec.js
new file mode 100644
index 0000000..45d95ac
--- /dev/null
+++ b/src/fauxton/test/core/routeObjectSpec.js
@@ -0,0 +1,91 @@
+define([
+       'api',
+      'testUtils'
+], function (FauxtonAPI, testUtils) {
+  var assert = testUtils.assert,
+      RouteObject = FauxtonAPI.RouteObject;
+
+  describe('RouteObjects', function () {
+
+    describe('renderWith', function () {
+      var TestRouteObject, testRouteObject, mockLayout;
+
+      beforeEach(function () {
+        TestRouteObject = RouteObject.extend({
+          crumbs: ['mycrumbs']
+        });
+
+        testRouteObject = new TestRouteObject();
+
+        // Need to find a better way of doing this
+        mockLayout = {
+          setTemplate: sinon.spy(),
+          clearBreadcrumbs: sinon.spy(),
+          setView: sinon.spy(),
+          renderView: sinon.spy(),
+          hooks: [],
+          setBreadcrumbs: sinon.spy()
+        };
+
+      });
+
+      it('Should set template for first render ', function () {
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+
+        assert.ok(mockLayout.setTemplate.calledOnce, 'setTempalte was called');
+      });
+
+      it('Should not set template after first render', function () {
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+
+        assert.ok(mockLayout.setTemplate.calledOnce, 'SetTemplate not meant to be called');
+      });
+
+      it('Should clear breadcrumbs', function () {
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+        assert.ok(mockLayout.clearBreadcrumbs.calledOnce, 'Clear Breadcrumbs called');
+      });
+
+      it('Should set breadcrumbs when breadcrumbs exist', function () {
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+        assert.ok(mockLayout.setBreadcrumbs.calledOnce, 'Set Breadcrumbs was called');
+      });
+
+      it("Should call establish of routeObject", function () {
+        var establishSpy = sinon.spy(testRouteObject,"establish");
+
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+        assert.ok(establishSpy.calledOnce, 'Calls establish');
+      });
+
+      it("Should render views", function () {
+        var view = new FauxtonAPI.View(),
+            getViewsSpy = sinon.stub(testRouteObject,"getViews"),
+            viewSpy = sinon.stub(view, "establish");
+        
+        sinon.stub(view, "hasRendered").returns(false);
+        getViewsSpy.returns({'#view': view});
+
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+        assert.ok(viewSpy.calledOnce, 'Should render view');
+      });
+
+      it("Should not re-render a view", function () {
+        var view = new FauxtonAPI.View(),
+            getViewsSpy = sinon.stub(testRouteObject,"getViews"),
+            viewSpy = sinon.stub(view, "establish");
+        
+        sinon.stub(view, "hasRendered").returns(true);
+        getViewsSpy.returns({'#view': view});
+
+        testRouteObject.renderWith('the-route', mockLayout, 'args');
+        assert.notOk(viewSpy.calledOnce, 'Should render view');
+      });
+    });
+
+  });
+
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/test/jasmine/index.html
----------------------------------------------------------------------
diff --git a/src/fauxton/test/jasmine/index.html b/src/fauxton/test/jasmine/index.html
deleted file mode 100644
index 8905580..0000000
--- a/src/fauxton/test/jasmine/index.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <meta name="viewport" content="width=device-width,initial-scale=1">
-
-  <title>Backbone Boilerplate Jasmine Test Suite</title>
-
-  <!-- Jasmine styles -->
-  <link rel="stylesheet" href="vendor/jasmine.css">
-</head>
-
-<body>
-  <!-- Testing libs -->
-  <script src="vendor/jasmine.js"></script>
-  <script src="vendor/jasmine-html.js"></script>
-
-  <!-- Application libs -->
-  <script src="../../assets/js/libs/jquery.js"></script>
-  <script src="../../assets/js/libs/lodash.js"></script>
-  <script src="../../assets/js/libs/backbone.js"></script>
-  
-  <!-- Load application -->
-  <script data-main="../../app/config"
-    src="../../assets/js/libs/require.js"></script>
-
-  <!-- Declare your spec files to be run here -->
-  <script>
-    // Ensure you point to where your spec folder is, base directory is app/,
-    // which is why ../test is necessary
-    require({ paths: { spec: "../test/jasmine/spec" } }, [
-
-      // Load the example spec, replace this and add your own spec
-      "spec/example"
-
-    ], function() {
-      // Set up the jasmine reporters once each spec has been loaded
-      jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
-      jasmine.getEnv().execute();
-    });
-  </script>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/test/jasmine/spec/example.js
----------------------------------------------------------------------
diff --git a/src/fauxton/test/jasmine/spec/example.js b/src/fauxton/test/jasmine/spec/example.js
deleted file mode 100644
index bbba3e8..0000000
--- a/src/fauxton/test/jasmine/spec/example.js
+++ /dev/null
@@ -1,73 +0,0 @@
-describe("one tautology", function() {
-  it("is a tautology", function() {
-    expect(true).toBeTruthy();
-  });
-
-  describe("is awesome", function() {
-    it("is awesome", function() {
-      expect(1).toBe(1);
-    });
-  });
-});
-
-describe("simple tests", function() {
-  it("increments", function() {
-    var mike = 0;
-
-    expect(mike++ === 0).toBeTruthy();
-    expect(mike === 1).toBeTruthy();
-  });
-
-  it("increments (improved)", function() {
-    var mike = 0;
-
-    expect(mike++).toBe(0);
-    expect(mike).toBe(1);
-  });
-});
-
-describe("setUp/tearDown", function() {
-  beforeEach(function() {
-    // console.log("Before");
-  });
-
-  afterEach(function() {
-    // console.log("After");
-  });
-
-  it("example", function() {
-    // console.log("During");
-  });
-
-  describe("setUp/tearDown", function() {
-    beforeEach(function() {
-      // console.log("Before2");
-    });
-
-    afterEach(function() {
-      // console.log("After2");
-    });
-
-    it("example", function() {
-      // console.log("During Nested");
-    });
-  });
-});
-
-describe("async", function() {
-  it("multiple async", function() {
-    var semaphore = 2;
-
-    setTimeout(function() {
-      expect(true).toBeTruthy();
-      semaphore--;
-    }, 500);
-
-    setTimeout(function() {
-      expect(true).toBeTruthy();
-      semaphore--;
-    }, 500);
-
-    waitsFor(function() { return semaphore === 0 });
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/test/jasmine/vendor/MIT.LICENSE
----------------------------------------------------------------------
diff --git a/src/fauxton/test/jasmine/vendor/MIT.LICENSE b/src/fauxton/test/jasmine/vendor/MIT.LICENSE
deleted file mode 100644
index 7c435ba..0000000
--- a/src/fauxton/test/jasmine/vendor/MIT.LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2008-2011 Pivotal Labs
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/test/jasmine/vendor/jasmine-html.js
----------------------------------------------------------------------
diff --git a/src/fauxton/test/jasmine/vendor/jasmine-html.js b/src/fauxton/test/jasmine/vendor/jasmine-html.js
deleted file mode 100644
index 7383401..0000000
--- a/src/fauxton/test/jasmine/vendor/jasmine-html.js
+++ /dev/null
@@ -1,190 +0,0 @@
-jasmine.TrivialReporter = function(doc) {
-  this.document = doc || document;
-  this.suiteDivs = {};
-  this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
-  var el = document.createElement(type);
-
-  for (var i = 2; i < arguments.length; i++) {
-    var child = arguments[i];
-
-    if (typeof child === 'string') {
-      el.appendChild(document.createTextNode(child));
-    } else {
-      if (child) { el.appendChild(child); }
-    }
-  }
-
-  for (var attr in attrs) {
-    if (attr == "className") {
-      el[attr] = attrs[attr];
-    } else {
-      el.setAttribute(attr, attrs[attr]);
-    }
-  }
-
-  return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
-  var showPassed, showSkipped;
-
-  this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
-      this.createDom('div', { className: 'banner' },
-        this.createDom('div', { className: 'logo' },
-            this.createDom('span', { className: 'title' }, "Jasmine"),
-            this.createDom('span', { className: 'version' }, runner.env.versionString())),
-        this.createDom('div', { className: 'options' },
-            "Show ",
-            showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
-            this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
-            showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
-            this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
-            )
-          ),
-
-      this.runnerDiv = this.createDom('div', { className: 'runner running' },
-          this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
-          this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
-          this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
-      );
-
-  this.document.body.appendChild(this.outerDiv);
-
-  var suites = runner.suites();
-  for (var i = 0; i < suites.length; i++) {
-    var suite = suites[i];
-    var suiteDiv = this.createDom('div', { className: 'suite' },
-        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
-        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
-    this.suiteDivs[suite.id] = suiteDiv;
-    var parentDiv = this.outerDiv;
-    if (suite.parentSuite) {
-      parentDiv = this.suiteDivs[suite.parentSuite.id];
-    }
-    parentDiv.appendChild(suiteDiv);
-  }
-
-  this.startedAt = new Date();
-
-  var self = this;
-  showPassed.onclick = function(evt) {
-    if (showPassed.checked) {
-      self.outerDiv.className += ' show-passed';
-    } else {
-      self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
-    }
-  };
-
-  showSkipped.onclick = function(evt) {
-    if (showSkipped.checked) {
-      self.outerDiv.className += ' show-skipped';
-    } else {
-      self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
-    }
-  };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
-  var results = runner.results();
-  var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
-  this.runnerDiv.setAttribute("class", className);
-  //do it twice for IE
-  this.runnerDiv.setAttribute("className", className);
-  var specs = runner.specs();
-  var specCount = 0;
-  for (var i = 0; i < specs.length; i++) {
-    if (this.specFilter(specs[i])) {
-      specCount++;
-    }
-  }
-  var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
-  message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
-  this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
-  this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
-  var results = suite.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.totalCount === 0) { // todo: change this to check results.skipped
-    status = 'skipped';
-  }
-  this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
-  if (this.logRunningSpecs) {
-    this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
-  }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
-  var results = spec.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.skipped) {
-    status = 'skipped';
-  }
-  var specDiv = this.createDom('div', { className: 'spec '  + status },
-      this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(spec.getFullName()),
-        title: spec.getFullName()
-      }, spec.description));
-
-
-  var resultItems = results.getItems();
-  var messagesDiv = this.createDom('div', { className: 'messages' });
-  for (var i = 0; i < resultItems.length; i++) {
-    var result = resultItems[i];
-
-    if (result.type == 'log') {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
-    } else if (result.type == 'expect' && result.passed && !result.passed()) {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
-      if (result.trace.stack) {
-        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
-      }
-    }
-  }
-
-  if (messagesDiv.childNodes.length > 0) {
-    specDiv.appendChild(messagesDiv);
-  }
-
-  this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
-  var console = jasmine.getGlobal().console;
-  if (console && console.log) {
-    if (console.log.apply) {
-      console.log.apply(console, arguments);
-    } else {
-      console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
-    }
-  }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
-  return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
-  var paramMap = {};
-  var params = this.getLocation().search.substring(1).split('&');
-  for (var i = 0; i < params.length; i++) {
-    var p = params[i].split('=');
-    paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
-  }
-
-  if (!paramMap.spec) {
-    return true;
-  }
-  return spec.getFullName().indexOf(paramMap.spec) === 0;
-};

http://git-wip-us.apache.org/repos/asf/couchdb/blob/9e5eb17d/src/fauxton/test/jasmine/vendor/jasmine.css
----------------------------------------------------------------------
diff --git a/src/fauxton/test/jasmine/vendor/jasmine.css b/src/fauxton/test/jasmine/vendor/jasmine.css
deleted file mode 100644
index 6583fe7..0000000
--- a/src/fauxton/test/jasmine/vendor/jasmine.css
+++ /dev/null
@@ -1,166 +0,0 @@
-body {
-  font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
-}
-
-
-.jasmine_reporter a:visited, .jasmine_reporter a {
-  color: #303; 
-}
-
-.jasmine_reporter a:hover, .jasmine_reporter a:active {
-  color: blue; 
-}
-
-.run_spec {
-  float:right;
-  padding-right: 5px;
-  font-size: .8em;
-  text-decoration: none;
-}
-
-.jasmine_reporter {
-  margin: 0 5px;
-}
-
-.banner {
-  color: #303;
-  background-color: #fef;
-  padding: 5px;
-}
-
-.logo {
-  float: left;
-  font-size: 1.1em;
-  padding-left: 5px;
-}
-
-.logo .version {
-  font-size: .6em;
-  padding-left: 1em;
-}
-
-.runner.running {
-  background-color: yellow;
-}
-
-
-.options {
-  text-align: right;
-  font-size: .8em;
-}
-
-
-
-
-.suite {
-  border: 1px outset gray;
-  margin: 5px 0;
-  padding-left: 1em;
-}
-
-.suite .suite {
-  margin: 5px; 
-}
-
-.suite.passed {
-  background-color: #dfd;
-}
-
-.suite.failed {
-  background-color: #fdd;
-}
-
-.spec {
-  margin: 5px;
-  padding-left: 1em;
-  clear: both;
-}
-
-.spec.failed, .spec.passed, .spec.skipped {
-  padding-bottom: 5px;
-  border: 1px solid gray;
-}
-
-.spec.failed {
-  background-color: #fbb;
-  border-color: red;
-}
-
-.spec.passed {
-  background-color: #bfb;
-  border-color: green;
-}
-
-.spec.skipped {
-  background-color: #bbb;
-}
-
-.messages {
-  border-left: 1px dashed gray;
-  padding-left: 1em;
-  padding-right: 1em;
-}
-
-.passed {
-  background-color: #cfc;
-  display: none;
-}
-
-.failed {
-  background-color: #fbb;
-}
-
-.skipped {
-  color: #777;
-  background-color: #eee;
-  display: none;
-}
-
-
-/*.resultMessage {*/
-  /*white-space: pre;*/
-/*}*/
-
-.resultMessage span.result {
-  display: block;
-  line-height: 2em;
-  color: black;
-}
-
-.resultMessage .mismatch {
-  color: black;
-}
-
-.stackTrace {
-  white-space: pre;
-  font-size: .8em;
-  margin-left: 10px;
-  max-height: 5em;
-  overflow: auto;
-  border: 1px inset red;
-  padding: 1em;
-  background: #eef;
-}
-
-.finished-at {
-  padding-left: 1em;
-  font-size: .6em;
-}
-
-.show-passed .passed,
-.show-skipped .skipped {
-  display: block;
-}
-
-
-#jasmine_content {
-  position:fixed;
-  right: 100%;
-}
-
-.runner {
-  border: 1px solid gray;
-  display: block;
-  margin: 5px 0;
-  padding: 2px 0 2px 10px;
-}