100%
diff --git a/README.md b/README.md
index 96af404..68c17a8 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,6 @@
* **errors** - errors are proxied directly from couchdb: if you know couchdb
you already know `nano`.
-
## installation
1. install [npm][1]
@@ -23,45 +22,45 @@
- [tutorials & screencasts](#tutorials-examples-in-the-wild--screencasts)
- [configuration](#configuration)
- [database functions](#database-functions)
- - [nano.db.create(name, [callback])](#nanodbcreatename-callback)
- - [nano.db.get(name, [callback])](#nanodbgetname-callback)
- - [nano.db.destroy(name, [callback])](#nanodbdestroyname-callback)
- - [nano.db.list([callback])](#nanodblistcallback)
- - [nano.db.compact(name, [designname], [callback])](#nanodbcompactname-designname-callback)
- - [nano.db.replicate(source, target, [opts], [callback])](#nanodbreplicatesource-target-opts-callback)
- - [nano.db.changes(name, [params], [callback])](#nanodbchangesname-params-callback)
- - [nano.db.follow(name, [params], [callback])](#nanodbfollowname-params-callback)
- - [nano.use(name)](#nanousename)
- - [nano.request(opts, [callback])](#nanorequestopts-callback)
- - [nano.config](#nanoconfig)
- - [nano.updates([params], [callback])](#nanoupdatesparams-callback)
- - [nano.follow_updates([params], [callback])](#nanofollow_updatesparams-callback)
+ - [nano.db.create(name, [callback])](#nanodbcreatename-callback)
+ - [nano.db.get(name, [callback])](#nanodbgetname-callback)
+ - [nano.db.destroy(name, [callback])](#nanodbdestroyname-callback)
+ - [nano.db.list([callback])](#nanodblistcallback)
+ - [nano.db.compact(name, [designname], [callback])](#nanodbcompactname-designname-callback)
+ - [nano.db.replicate(source, target, [opts], [callback])](#nanodbreplicatesource-target-opts-callback)
+ - [nano.db.changes(name, [params], [callback])](#nanodbchangesname-params-callback)
+ - [nano.db.follow(name, [params], [callback])](#nanodbfollowname-params-callback)
+ - [nano.use(name)](#nanousename)
+ - [nano.request(opts, [callback])](#nanorequestopts-callback)
+ - [nano.config](#nanoconfig)
+ - [nano.updates([params], [callback])](#nanoupdatesparams-callback)
+ - [nano.followUpdates([params], [callback])](#nanofollowUpdatesparams-callback)
- [document functions](#document-functions)
- - [db.insert(doc, [params], [callback])](#dbinsertdoc-params-callback)
- - [db.destroy(docname, rev, [callback])](#dbdestroydocname-rev-callback)
- - [db.get(docname, [params], [callback])](#dbgetdocname-params-callback)
- - [db.head(docname, [callback])](#dbheaddocname-callback)
- - [db.copy(src_doc, dest_doc, opts, [callback])](#dbcopysrc_doc-dest_doc-opts-callback)
- - [db.bulk(docs, [params], [callback])](#dbbulkdocs-params-callback)
- - [db.list([params], [callback])](#dblistparams-callback)
- - [db.fetch(docnames, [params], [callback])](#dbfetchdocnames-params-callback)
- - [db.fetch_revs(docnames, [params], [callback])](#dbfetch_revsdocnames-params-callback)
+ - [db.insert(doc, [params], [callback])](#dbinsertdoc-params-callback)
+ - [db.destroy(docname, rev, [callback])](#dbdestroydocname-rev-callback)
+ - [db.get(docname, [params], [callback])](#dbgetdocname-params-callback)
+ - [db.head(docname, [callback])](#dbheaddocname-callback)
+ - [db.copy(src_doc, dest_doc, opts, [callback])](#dbcopysrc_doc-dest_doc-opts-callback)
+ - [db.bulk(docs, [params], [callback])](#dbbulkdocs-params-callback)
+ - [db.list([params], [callback])](#dblistparams-callback)
+ - [db.fetch(docnames, [params], [callback])](#dbfetchdocnames-params-callback)
+ - [db.fetchRevs(docnames, [params], [callback])](#dbfetchRevsdocnames-params-callback)
- [multipart functions](#multipart-functions)
- - [db.multipart.insert(doc, attachments, [params], [callback])](#dbmultipartinsertdoc-attachments-params-callback)
- - [db.multipart.get(docname, [params], [callback])](#dbmultipartgetdocname-params-callback)
+ - [db.multipart.insert(doc, attachments, [params], [callback])](#dbmultipartinsertdoc-attachments-params-callback)
+ - [db.multipart.get(docname, [params], [callback])](#dbmultipartgetdocname-params-callback)
- [attachments functions](#attachments-functions)
- - [db.attachment.insert(docname, attname, att, contenttype, [params], [callback])](#dbattachmentinsertdocname-attname-att-contenttype-params-callback)
- - [db.attachment.get(docname, attname, [params], [callback])](#dbattachmentgetdocname-attname-params-callback)
- - [db.attachment.destroy(docname, attname, rev, [callback])](#dbattachmentdestroydocname-attname-rev-callback)
+ - [db.attachment.insert(docname, attname, att, contenttype, [params], [callback])](#dbattachmentinsertdocname-attname-att-contenttype-params-callback)
+ - [db.attachment.get(docname, attname, [params], [callback])](#dbattachmentgetdocname-attname-params-callback)
+ - [db.attachment.destroy(docname, attname, [params], [callback])](#dbattachmentdestroydocname-attname-rev-callback)
- [views and design functions](#views-and-design-functions)
- - [db.view(designname, viewname, [params], [callback])](#dbviewdesignname-viewname-params-callback)
- - [db.show(designname, showname, doc_id, [params], [callback])](#dbshowdesignname-showname-doc_id-params-callback)
- - [db.atomic(designname, updatename, docname, [body], [callback])](#dbatomicdesignname-updatename-docname-body-callback)
- - [db.search(designname, viewname, [params], [callback])](#dbsearchdesignname-searchname-params-callback)
+ - [db.view(designname, viewname, [params], [callback])](#dbviewdesignname-viewname-params-callback)
+ - [db.show(designname, showname, doc_id, [params], [callback])](#dbshowdesignname-showname-doc_id-params-callback)
+ - [db.atomic(designname, updatename, docname, [body], [callback])](#dbatomicdesignname-updatename-docname-body-callback)
+ - [db.search(designname, viewname, [params], [callback])](#dbsearchdesignname-searchname-params-callback)
- [using cookie authentication](#using-cookie-authentication)
- [advanced features](#advanced-features)
- - [extending nano](#extending-nano)
- - [pipes](#pipes)
+ - [extending nano](#extending-nano)
+ - [pipes](#pipes)
- [tests](#tests)
## getting started
@@ -354,7 +353,7 @@
### nano.updates([params], [callback])
listen to db updates, the available `params` are:
-
+
* `params.feed` – Type of feed. Can be one of
* `longpoll`: Closes the connection after the first event.
* `continuous`: Send a line of JSON per event. Keeps the socket open until timeout.
@@ -363,14 +362,16 @@
* `params.heartbeat` – Whether CouchDB will send a newline character (\n) on timeout. Default is true.
-### nano.follow_updates([params], [callback])
+### nano.followUpdates([params], [callback])
+
+** changed in version 6 **
uses [follow](https://github.com/iriscouch/follow) to create a solid
[`_db_updates`](http://docs.couchdb.org/en/latest/api/server/common.html?highlight=db_updates#get--_db_updates) feed.
please consult follow documentation for more information as this is a very complete api on it's own
```js
-var feed = nano.follow_updates({since: "now"});
+var feed = nano.followUpdates({since: "now"});
feed.on('change', function (change) {
console.log("change: ", change);
});
@@ -467,7 +468,9 @@
additional query string `params` can be specified, `include_docs` is always set
to `true`.
-### db.fetch_revs(docnames, [params], [callback])
+### db.fetchRevs(docnames, [params], [callback])
+
+** changed in version 6 **
bulk fetch of the revisions of the database documents, `docnames` are specified as per
[couchdb doc](http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API).
@@ -564,13 +567,15 @@
alice.attachment.get('rabbit', 'rabbit.png').pipe(fs.createWriteStream('rabbit.png'));
```
-### db.attachment.destroy(docname, attname, rev, [callback])
+### db.attachment.destroy(docname, attname, [params], [callback])
+
+**changed in version 6**
destroy attachment `attname` of `docname`'s revision `rev`.
``` js
alice.attachment.destroy('rabbit', 'rabbit.png',
- '1-4701d73a08ce5c2f2983bf7c9ffd3320', function(err, body) {
+ {rev: '1-4701d73a08ce5c2f2983bf7c9ffd3320'}, function(err, body) {
if (!err)
console.log(body);
});
diff --git a/lib/nano.js b/lib/nano.js
index b8e0dbd..8c540fa 100644
--- a/lib/nano.js
+++ b/lib/nano.js
@@ -29,7 +29,7 @@
var httpAgent = (typeof cfg.request === 'function') ? cfg.request :
request.defaults(cfg.requestDefaults);
-
+ var followAgent = (typeof cfg.follow === 'function') ? cfg.follow : follow;
var log = typeof cfg.log === 'function' ? cfg.log : logger(cfg);
function relax(opts, callback) {
@@ -60,13 +60,14 @@
uri: cfg.url
};
- var statusCode;
var parsed;
var rh;
// https://github.com/mikeal/request#requestjar
- if (opts.jar) {
- req.jar = opts.jar;
+ var isJar = opts.jar || cfg.jar;
+
+ if (isJar) {
+ req.jar = isJar;
}
// http://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing
@@ -156,18 +157,17 @@
}
return httpAgent(req, function(e, h, b) {
- rh = (h && h.headers || {});
- rh.statusCode = (h && h.statusCode || 500);
+ rh = h && h.headers || {};
+ rh.statusCode = h && h.statusCode || 500;
rh.uri = req.uri;
if (e) {
log({err: 'socket', body: b, headers: rh});
- errs.handle(errs.merge(e, {
+ return callback(errs.merge(e, {
message: 'error happened in your connection',
scope: 'socket',
errid: 'request'
- }), callback);
- return;
+ }));
}
delete rh.server;
@@ -181,35 +181,31 @@
if (rh.statusCode >= 200 && rh.statusCode < 400) {
log({err: null, body: parsed, headers: rh});
-
- callback(null, parsed, rh);
+ return callback(null, parsed, rh);
}
- else { // proxy the error directly from couchdb
- log({err: 'couch', body: parsed, headers: rh});
- if (!parsed) {
- parsed = {};
- }
+ log({err: 'couch', body: parsed, headers: rh});
- // cloudant stacktrace
- if (typeof parsed === 'string') {
- parsed = {message: parsed};
- }
- if (!parsed.message && (parsed.reason || parsed.error)) {
- parsed.message = (parsed.reason || parsed.error);
- }
- // fix cloudant issues where they give an erlang stacktrace as js
- delete parsed.stack;
-
- errs.handle(errs.merge(errs.create(parsed), {
- scope: 'couch',
- statusCode: rh.statusCode,
- request: req,
- headers: rh,
- errid: 'non_200',
- message: parsed.reason || 'couch returned ' + statusCode
- }), callback);
+ // cloudant stacktrace
+ if (typeof parsed === 'string') {
+ parsed = {message: parsed};
}
+
+ if (!parsed.message && (parsed.reason || parsed.error)) {
+ parsed.message = (parsed.reason || parsed.error);
+ }
+
+ // fix cloudant issues where they give an erlang stacktrace as js
+ delete parsed.stack;
+
+ callback(errs.merge({
+ message: 'couch returned ' + rh.statusCode,
+ scope: 'couch',
+ statusCode: rh.statusCode,
+ request: req,
+ headers: rh,
+ errid: 'non_200'
+ }, errs.create(parsed)));
});
}
@@ -295,13 +291,12 @@
qs = {};
}
- qs = qs || {};
qs.db = u.resolve(cfg.url, encodeURIComponent(dbName));
if (typeof callback === 'function') {
- return follow(qs, callback);
+ return followAgent(qs, callback);
} else {
- return new follow.Feed(qs);
+ return new followAgent.Feed(qs);
}
}
@@ -328,6 +323,7 @@
function docModule(dbName) {
var docScope = {};
+ dbName = decodeURIComponent(dbName);
// http://docs.couchdb.org/en/latest/api/document/common.html#put--db-docid
// http://docs.couchdb.org/en/latest/api/database/common.html#post--db
@@ -455,14 +451,13 @@
}, callback);
}
- // http://docs.couchdb.org/en/latest/api/ddoc/views.html#post--db-_design-ddoc-_view-view
- function viewDocs(ddoc, viewName, qs, callback) {
+ function view(ddoc, viewName, meta, qs, callback) {
if (typeof qs === 'function') {
callback = qs;
qs = {};
}
- var viewPath = '_design/' + ddoc + '/_view/' + viewName;
+ var viewPath = '_design/' + ddoc + '/_' + meta.type + '/' + viewName;
if (qs && qs.keys) {
var body = {keys: qs.keys};
@@ -474,62 +469,57 @@
qs: qs,
body: body
}, callback);
+ } else {
+ var req = {
+ db: dbName,
+ method: meta.method || 'GET',
+ path: viewPath,
+ qs: qs
+ };
+
+ if (meta.body) {
+ req.body = meta.body;
+ }
+
+ return relax(req, callback);
}
- else {
- return relax({db: dbName, path: viewPath, qs: qs}, callback);
- }
+ }
+
+ // http://docs.couchdb.org/en/latest/api/ddoc/views.html#post--db-_design-ddoc-_view-view
+ function viewDocs(ddoc, viewName, qs, callback) {
+ return view(ddoc, viewName, {type: 'view'}, qs, callback);
}
// geocouch
function viewSpatial(ddoc, viewName, qs, callback) {
- if (typeof qs === 'function') {
- callback = qs;
- qs = {};
- }
-
- var viewPath = '_design/' + ddoc + '/_spatial/' + viewName;
-
- return relax({db: dbName, path: viewPath, qs: qs}, callback);
+ return view(ddoc, viewName, {type: 'spatial'}, qs, callback);
}
// cloudant
- function viewSearch(ddoc, searchName, qs, callback) {
- if (typeof qs === 'function') {
- callback = qs;
- qs = {};
- }
-
- var viewPath = '_design/' + ddoc + '/_search/' + searchName;
-
- return relax({db: dbName, path: viewPath, qs: qs}, callback);
+ function viewSearch(ddoc, viewName, qs, callback) {
+ return view(ddoc, viewName, {type: 'search'}, qs, callback);
}
// http://docs.couchdb.org/en/latest/api/ddoc/render.html#get--db-_design-ddoc-_show-func
- function showDoc(ddoc, fn, docId, qs, callback) {
- if (typeof qs === 'function') {
- callback = qs;
- qs = {};
- }
-
- var show = '_design/' + ddoc + '/_show/' + fn + '/' + docId;
-
- return relax({db: dbName, path: show, qs: qs}, callback);
+ function showDoc(ddoc, viewName, docName, qs, callback) {
+ return view(ddoc, viewName + '/' + docName, {type: 'show'}, qs, callback);
}
// http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid
- function updateWithHandler(ddoc, updateName, docName, body, callback) {
-
- var updatePath = '_design/' + ddoc + '/_update/' + updateName +
- '/' + encodeURIComponent(docName);
-
- return relax({
- db: dbName,
- path: updatePath,
- method: 'PUT',
- body: body
+ function updateWithHandler(ddoc, viewName, docName, body, callback) {
+ return view(ddoc, viewName + '/' + encodeURIComponent(docName), {
+ type: 'update',
+ method: 'PUT',
+ body: body
}, callback);
}
+ function viewWithList(ddoc, viewName, listName, qs, callback) {
+ return view(ddoc, listName + '/' + viewName, {
+ type: 'list'
+ }, qs, callback);
+ }
+
// http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_bulksDoc
function bulksDoc(docs, qs, callback) {
if (typeof qs === 'function') {
@@ -634,41 +624,16 @@
}, callback);
}
- function destroyAtt(docName, attName, rev, callback) {
+ function destroyAtt(docName, attName, qs, callback) {
return relax({
db: dbName,
att: attName,
method: 'DELETE',
doc: docName,
- qs: {rev: rev}
+ qs: qs
}, callback);
}
- function viewWithList(ddoc, viewName, listName, qs, callback) {
-
- var listPath = '_design/' + ddoc + '/_list/' +
- listName + '/' + viewName;
-
- if (qs && qs.keys) {
- var body = {keys: qs.keys};
- delete qs.keys;
- return relax({
- db: dbName,
- path: listPath,
- method: 'POST',
- qs: qs,
- body: body
- }, callback);
- }
- else {
- return relax({
- db: dbName,
- path: listPath,
- qs: qs
- }, callback);
- }
- }
-
// db level exports
docScope = {
info: function(cb) {
@@ -735,7 +700,9 @@
compact: compactDb,
replicate: replicateDb,
changes: changesDb,
- follow: followDb
+ follow: followDb,
+ followUpdates: followUpdates,
+ updates: updates
},
use: docModule,
scope: docModule,
@@ -755,7 +722,7 @@
auth = path.auth ? path.auth : '';
var port = path.port ? ':' + path.port : '';
- var db = cfg.db ? cfg.db : decodeURIComponent(pathArray[0]);
+ var db = pathArray[0];
var format = {
protocol: path.protocol,
@@ -766,10 +733,6 @@
format.auth = auth;
}
- if (cfg.db) {
- format.pathname = path.pathname + '/';
- }
-
cfg.url = u.format(format);
return docModule(db);
diff --git a/tests/fixtures/shared/log.json b/tests/fixtures/shared/log.json
new file mode 100644
index 0000000..6ed417e
--- /dev/null
+++ b/tests/fixtures/shared/log.json
@@ -0,0 +1,11 @@
+[
+ { "method" : "put"
+ , "path" : "/shared_log"
+ , "status" : 201
+ , "response" : "{ \"ok\": true }"
+ }
+, { "method" : "delete"
+ , "path" : "/shared_log"
+ , "response" : "{ \"ok\": true }"
+ }
+]
diff --git a/tests/helpers/index.js b/tests/helpers/index.js
new file mode 100644
index 0000000..dd177b3
--- /dev/null
+++ b/tests/helpers/index.js
@@ -0,0 +1,28 @@
+'use strict';
+
+var path = require('path');
+var fs = require('fs');
+var url = require('url');
+var nano = require('../../lib/nano');
+
+var helpers = exports;
+var cfg = helpers.cfg = require('../fixtures/cfg');
+var auth = url.parse(cfg.admin).auth.split(':');
+
+helpers.timeout = cfg.timeout;
+helpers.nano = nano(cfg.couch);
+helpers.Nano = nano;
+helpers.couch = cfg.couch;
+helpers.admin = cfg.admin;
+helpers.pixel = 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BABgAAAAA' +
+ 'AAAAAAATCwAAEwsAAAAAAAAAAAAAWm2CAA==';
+
+helpers.username = auth[0];
+helpers.password = auth[1];
+
+helpers.loadFixture = function helpersLoadFixture(filename, json) {
+ var contents = fs.readFileSync(
+ path.join(__dirname, '..', 'fixtures', filename), (json ? 'ascii' : null));
+ return json ? JSON.parse(contents) : contents;
+};
+
diff --git a/tests/helpers.js b/tests/helpers/integration.js
similarity index 77%
rename from tests/helpers.js
rename to tests/helpers/integration.js
index 4a005b9..1b5e1ba 100644
--- a/tests/helpers.js
+++ b/tests/helpers/integration.js
@@ -1,35 +1,13 @@
'use strict';
var async = require('async');
-var path = require('path');
-var fs = require('fs');
-var url = require('url');
-var harness = require('tape-it');
var debug = require('debug');
var path = require('path');
+var harness = require('tape-it');
var endsWith = require('endswith');
-var cfg = require('./fixtures/cfg');
-var nano = require('../lib/nano');
-var helpers = exports;
-
-var auth = url.parse(cfg.admin).auth.split(':');
-
-helpers.timeout = cfg.timeout;
-helpers.nano = nano(cfg.couch);
-helpers.Nano = nano;
-helpers.couch = cfg.couch;
-helpers.admin = cfg.admin;
-helpers.pixel = 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BABgAAAAA' +
- 'AAAAAAATCwAAEwsAAAAAAAAAAAAAWm2CAA==';
-
-helpers.username = auth[0];
-helpers.password = auth[1];
-
-helpers.loadFixture = function helpersLoadFixture(filename, json) {
- var contents = fs.readFileSync(
- path.join(__dirname, 'fixtures', filename), (json ? 'ascii' : null));
- return json ? JSON.parse(contents) : contents;
-};
+var cfg = require('../fixtures/cfg');
+var nano = require('../../lib/nano');
+var helpers = require('./');
helpers.setup = function() {
var self = this;
@@ -60,27 +38,20 @@
};
};
-helpers.noopTest = function (assert) {
- assert.pass('werk werk werk');
- assert.end();
-};
-
-helpers.harness = function(name, unit) {
- unit = !!unit;
-
+helpers.harness = function(name) {
var parent = name || module.parent.filename;
var fileName = path.basename(parent).split('.')[0];
var parentDir = path.dirname(parent)
.split(path.sep).reverse()[0];
var shortPath = path.join(parentDir, fileName);
- var log = debug(path.join('nano', 'tests', shortPath));
+ var log = debug(path.join('nano', 'tests', 'integration', shortPath));
var dbName = shortPath.replace('/', '_');
var nanoLog = nano({
url: cfg.couch,
log: log
});
- var mock = unit ? null : helpers.nock(helpers.couch, shortPath, log);
+ var mock = helpers.nock(helpers.couch, shortPath, log);
var db = nanoLog.use(dbName);
var locals = {
mock: mock,
@@ -93,14 +64,14 @@
timeout: helpers.timeout,
checkLeaks: !!process.env.LEAKS,
locals: locals,
- setup: unit ? helpers.noopTest : helpers.setup.call(locals, dbName),
- teardown: unit ? helpers.noopTest : helpers.teardown.call(locals, dbName)
+ setup: helpers.setup.call(locals, dbName),
+ teardown: helpers.teardown.call(locals, dbName)
});
};
helpers.nock = function helpersNock(url, fixture, log) {
var nock = require('nock');
- var nockDefs = require('./fixtures/' + fixture + '.json');
+ var nockDefs = require('../fixtures/' + fixture + '.json');
nockDefs.forEach(function(n) {
var headers = n.headers || {};
@@ -204,3 +175,6 @@
helpers.unmocked = (process.env.NOCK_OFF === 'true');
helpers.mocked = !helpers.unmocked;
+
+module.exports = helpers;
+
diff --git a/tests/helpers/unit.js b/tests/helpers/unit.js
new file mode 100644
index 0000000..c47a30c
--- /dev/null
+++ b/tests/helpers/unit.js
@@ -0,0 +1,139 @@
+'use strict';
+
+var helpers = require('./');
+var Client = require('../../lib/nano');
+var test = require('tape');
+var _ = require('underscore');
+
+helpers.unit = function(method, error) {
+ var unitName = 'nano/tests/unit/' + method.join('/');
+ var debug = require('debug')(unitName);
+
+ function log(data) {
+ debug({ got: data.body });
+ }
+
+ var cli = helpers.mockClientOk(log, error);
+
+ //
+ // allow database creation and other server stuff
+ //
+ if(method[1].match(/follow/)) {
+ if(method[0] === 'database') {
+ cli.server = helpers.mockClientFollow(log, error);
+ } else {
+ cli = helpers.mockClientFollow(log, error);
+ }
+ } else {
+ cli.server = helpers.mockClientDb(log, error);
+ }
+
+ var testNr = 1;
+
+ return function() {
+ var args = Array.prototype.slice.call(arguments);
+ var stub = args.pop();
+
+ test(unitName + ':' + testNr++,
+ function(assert) {
+ var f;
+ assert.ok(typeof stub, 'object');
+
+ //
+ // document functions and database functions
+ // are at the top level in nano
+ //
+ if(method[0] === 'database') {
+ f = cli.server.db[method[1]];
+ } else if(method[0] === 'view' && method[1] === 'compact') {
+ f = cli.view.compact;
+ } else if(!~['multipart', 'attachment'].indexOf(method[0])) {
+ f = cli[method[1]];
+ } else {
+ f = cli[method[0]][method[1]];
+ }
+ assert.ok(typeof f, 'function');
+
+ args.push(function(err, req, response) {
+ if (error) {
+ assert.ok(err);
+ return assert.end();
+ }
+
+ assert.equal(response.statusCode, 200);
+ if(stub.uri) {
+ stub.uri = helpers.couch + stub.uri;
+ } else {
+ stub.db = helpers.couch + stub.db;
+ }
+
+ assert.deepEqual(req, stub);
+ assert.end();
+ });
+
+ f.apply(null, args);
+ });
+ };
+};
+
+function mockClient(code, path, extra) {
+ return function(debug, error) {
+ extra = extra || {};
+ var opts = _.extend(extra, {
+ url: helpers.couch + path,
+ log: debug,
+ request: function(req, cb) {
+ if(error) {
+ return cb(error);
+ }
+
+ if(code === 500) {
+ cb(new Error('omg connection failed'));
+ } else {
+ cb(null, {
+ statusCode: code,
+ headers: {}
+ }, req); }
+ }
+ });
+
+ return Client(opts);
+ };
+}
+
+function mockClientUnparsedError() {
+ return function(debug, body) {
+ return Client({
+ url: helpers.couch,
+ log: debug,
+ request: function(_, cb) {
+ return cb(null, {statusCode: 500}, body || '<b> Error happened </b>');
+ }
+ });
+ };
+}
+
+function mockClientFollow() {
+ return function(debug, error) {
+ return Client({
+ url: helpers.couch,
+ log: debug,
+ follow: function(qs, cb) {
+ if(error) {
+ return cb(error);
+ }
+
+ return cb(null, qs, {statusCode: 200});
+ }
+ });
+ };
+}
+
+
+helpers.mockClientFollow = mockClientFollow();
+helpers.mockClientUnparsedError = mockClientUnparsedError();
+helpers.mockClientDb = mockClient(200, '');
+helpers.mockClientOk = mockClient(200, '/mock');
+helpers.mockClientFail = mockClient(500, '');
+helpers.mockClientJar = mockClient(300, '', {jar: 'is set'});
+module.exports = helpers;
diff --git a/tests/integration/attachment/destroy.js b/tests/integration/attachment/destroy.js
index be0fc1f..30209fe 100644
--- a/tests/integration/attachment/destroy.js
+++ b/tests/integration/attachment/destroy.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
@@ -11,8 +11,8 @@
assert.equal(error, null, 'store the attachment');
assert.equal(att.ok, true, 'response ok');
assert.ok(att.rev, 'have a revision number');
- db.attachment.destroy('new', 'att',
- att.rev, function(error, response) {
+ db.attachment.destroy('new', 'att', {rev: att.rev},
+ function(error, response) {
assert.equal(error, null, 'delete the attachment');
assert.equal(response.ok, true, 'response ok');
assert.equal(response.id, 'new', '`id` should be `new`');
diff --git a/tests/integration/attachment/get.js b/tests/integration/attachment/get.js
index 2b4c556..7e642ac 100644
--- a/tests/integration/attachment/get.js
+++ b/tests/integration/attachment/get.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/attachment/insert.js b/tests/integration/attachment/insert.js
index 0e214d1..883bdcf 100644
--- a/tests/integration/attachment/insert.js
+++ b/tests/integration/attachment/insert.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/attachment/pipe.js b/tests/integration/attachment/pipe.js
index da3284b..5b9f7f9 100644
--- a/tests/integration/attachment/pipe.js
+++ b/tests/integration/attachment/pipe.js
@@ -2,7 +2,7 @@
var fs = require('fs');
var path = require('path');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/attachment/update.js b/tests/integration/attachment/update.js
index 39d8d26..bf0fc73 100644
--- a/tests/integration/attachment/update.js
+++ b/tests/integration/attachment/update.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var pixel = helpers.pixel;
var harness = helpers.harness(__filename);
var db = harness.locals.db;
diff --git a/tests/integration/database/changes.js b/tests/integration/database/changes.js
index 4082854..8d5f831 100644
--- a/tests/integration/database/changes.js
+++ b/tests/integration/database/changes.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/database/compact.js b/tests/integration/database/compact.js
index 18616ec..770772b 100644
--- a/tests/integration/database/compact.js
+++ b/tests/integration/database/compact.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/database/create-and-destroy.js b/tests/integration/database/create-and-destroy.js
index f50264b..899097b 100644
--- a/tests/integration/database/create-and-destroy.js
+++ b/tests/integration/database/create-and-destroy.js
@@ -1,7 +1,7 @@
'use strict';
var async = require('async');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var nano = harness.locals.nano;
diff --git a/tests/integration/database/follow.js b/tests/integration/database/follow.js
index 318105f..628c934 100644
--- a/tests/integration/database/follow.js
+++ b/tests/integration/database/follow.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/database/get.js b/tests/integration/database/get.js
index ca7808b..9f01985 100644
--- a/tests/integration/database/get.js
+++ b/tests/integration/database/get.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var nano = harness.locals.nano;
diff --git a/tests/integration/database/list.js b/tests/integration/database/list.js
index 32df911..d632d7d 100644
--- a/tests/integration/database/list.js
+++ b/tests/integration/database/list.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var nano = harness.locals.nano;
diff --git a/tests/integration/database/replicate.js b/tests/integration/database/replicate.js
index 732a775..95d4d0d 100644
--- a/tests/integration/database/replicate.js
+++ b/tests/integration/database/replicate.js
@@ -1,13 +1,14 @@
'use strict';
var async = require('async');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
var nano = harness.locals.nano;
-var replica, replica2;
+var replica;
+var replica2;
it('should insert a bunch of items', helpers.insertThree);
diff --git a/tests/integration/design/atomic.js b/tests/integration/design/atomic.js
index f1c342a..53e801a 100644
--- a/tests/integration/design/atomic.js
+++ b/tests/integration/design/atomic.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/design/compact.js b/tests/integration/design/compact.js
index f83e322..caeefed 100644
--- a/tests/integration/design/compact.js
+++ b/tests/integration/design/compact.js
@@ -1,7 +1,7 @@
'use strict';
var async = require('async');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/design/list.js b/tests/integration/design/list.js
index 89eb018..d3cdac1 100644
--- a/tests/integration/design/list.js
+++ b/tests/integration/design/list.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/design/multiple.js b/tests/integration/design/multiple.js
index 7224a23..c1c8031 100644
--- a/tests/integration/design/multiple.js
+++ b/tests/integration/design/multiple.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/design/query.js b/tests/integration/design/query.js
index 0996f90..1333cf9 100644
--- a/tests/integration/design/query.js
+++ b/tests/integration/design/query.js
@@ -1,7 +1,7 @@
'use strict';
var async = require('async');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/design/search.js b/tests/integration/design/search.js
index 41209b6..996b47a 100644
--- a/tests/integration/design/search.js
+++ b/tests/integration/design/search.js
@@ -1,7 +1,7 @@
'use strict';
var async = require('async');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/design/show.js b/tests/integration/design/show.js
index e1e0c55..ce9f87e 100644
--- a/tests/integration/design/show.js
+++ b/tests/integration/design/show.js
@@ -1,7 +1,7 @@
'use strict';
var async = require('async');
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/document/bulk.js b/tests/integration/document/bulk.js
index ca0198e..2ef13ad 100644
--- a/tests/integration/document/bulk.js
+++ b/tests/integration/document/bulk.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/document/copy.js b/tests/integration/document/copy.js
index f12f848..a32128e 100644
--- a/tests/integration/document/copy.js
+++ b/tests/integration/document/copy.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/document/destroy.js b/tests/integration/document/destroy.js
index 03ecdc6..d39b63c 100644
--- a/tests/integration/document/destroy.js
+++ b/tests/integration/document/destroy.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var db = harness.locals.db;
diff --git a/tests/integration/document/fetch.js b/tests/integration/document/fetch.js
index bd12354..85c95d3 100644
--- a/tests/integration/document/fetch.js
+++ b/tests/integration/document/fetch.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/document/fetch_revs.js b/tests/integration/document/fetch_revs.js
index 194c7c3..c25af3a 100644
--- a/tests/integration/document/fetch_revs.js
+++ b/tests/integration/document/fetch_revs.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/document/get.js b/tests/integration/document/get.js
index c0cb0b8..20a6671 100644
--- a/tests/integration/document/get.js
+++ b/tests/integration/document/get.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/document/head.js b/tests/integration/document/head.js
index 61e69c4..9f6cc20 100644
--- a/tests/integration/document/head.js
+++ b/tests/integration/document/head.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/document/insert.js b/tests/integration/document/insert.js
index 33d1491..1a0caab 100644
--- a/tests/integration/document/insert.js
+++ b/tests/integration/document/insert.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/document/list.js b/tests/integration/document/list.js
index 56c003b..d76c3a3 100644
--- a/tests/integration/document/list.js
+++ b/tests/integration/document/list.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var nano = harness.locals.nano;
diff --git a/tests/integration/document/update.js b/tests/integration/document/update.js
index fa6a307..e259744 100644
--- a/tests/integration/document/update.js
+++ b/tests/integration/document/update.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/multipart/get.js b/tests/integration/multipart/get.js
index a15644e..f0158c7 100644
--- a/tests/integration/multipart/get.js
+++ b/tests/integration/multipart/get.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/multipart/insert.js b/tests/integration/multipart/insert.js
index 4c1a86b..04ff1b3 100644
--- a/tests/integration/multipart/insert.js
+++ b/tests/integration/multipart/insert.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var db = harness.locals.db;
var it = harness.it;
diff --git a/tests/integration/shared/config.js b/tests/integration/shared/config.js
index 4e18500..23089b6 100644
--- a/tests/integration/shared/config.js
+++ b/tests/integration/shared/config.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var nano = harness.locals.nano;
var Nano = helpers.Nano;
diff --git a/tests/integration/shared/cookie.js b/tests/integration/shared/cookie.js
index 204955c..e99a3cb 100644
--- a/tests/integration/shared/cookie.js
+++ b/tests/integration/shared/cookie.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var nano = harness.locals.nano;
var Nano = helpers.Nano;
diff --git a/tests/integration/shared/error.js b/tests/integration/shared/error.js
index 80b0eff..1ee80bb 100644
--- a/tests/integration/shared/error.js
+++ b/tests/integration/shared/error.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var nano = harness.locals.nano;
var Nano = helpers.Nano;
@@ -34,7 +34,7 @@
nano.db.destroy('say_wat_wat', function(error) {
assert.ok(error, 'an error');
assert.ok(error.message, 'a note');
- assert.equal(error.description, 'missing', 'is missing');
+ assert.equal(error.message, 'missing', 'is missing');
assert.end();
});
});
diff --git a/tests/integration/shared/headers.js b/tests/integration/shared/headers.js
index bcfd734..9ca43e8 100644
--- a/tests/integration/shared/headers.js
+++ b/tests/integration/shared/headers.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var nano = harness.locals.nano;
var db = harness.locals.db;
diff --git a/tests/unit/shared/log.js b/tests/integration/shared/log.js
similarity index 76%
rename from tests/unit/shared/log.js
rename to tests/integration/shared/log.js
index bf23038..ff7e3b3 100644
--- a/tests/unit/shared/log.js
+++ b/tests/integration/shared/log.js
@@ -1,17 +1,18 @@
+'use strict';
+
var logger = require('../../../lib/logger');
var helpers = require('../../helpers');
var harness = helpers.harness(__filename, true);
var it = harness.it;
-it('should be able to instantiate a log', function (assert) {
+it('should be able to instantiate a log', function(assert) {
var log = logger({
- log: function (id, msg) {
+ log: function(id, msg) {
assert.equal(typeof id, 'string', 'id is set `' + id + '`');
assert.equal(msg[0], 'testing 1234');
assert.end();
}
})();
- debugger
log('testing 1234');
});
diff --git a/tests/integration/shared/nano.js b/tests/integration/shared/nano.js
index 3ae1e69..ea011fe 100644
--- a/tests/integration/shared/nano.js
+++ b/tests/integration/shared/nano.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var Nano = helpers.Nano;
var it = harness.it;
diff --git a/tests/integration/shared/updates.js b/tests/integration/shared/updates.js
index e44e76e..7c12a4c 100644
--- a/tests/integration/shared/updates.js
+++ b/tests/integration/shared/updates.js
@@ -1,6 +1,6 @@
'use strict';
-var helpers = require('../../helpers');
+var helpers = require('../../helpers/integration');
var harness = helpers.harness(__filename);
var it = harness.it;
var nano = harness.locals.nano;
diff --git a/tests/unit/attachment/destroy.js b/tests/unit/attachment/destroy.js
new file mode 100644
index 0000000..56488ba
--- /dev/null
+++ b/tests/unit/attachment/destroy.js
@@ -0,0 +1,16 @@
+'use strict';
+
+var destroyAttachment = require('../../helpers/unit').unit([
+ 'attachment',
+ 'destroy'
+]);
+
+destroyAttachment('airplane-design', 'wings.pdf', {rev: '3'}, {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'DELETE',
+ qs: {rev: '3'},
+ uri: '/mock/airplane-design/wings.pdf'
+});
diff --git a/tests/unit/attachment/get.js b/tests/unit/attachment/get.js
new file mode 100644
index 0000000..c4c7510
--- /dev/null
+++ b/tests/unit/attachment/get.js
@@ -0,0 +1,21 @@
+'use strict';
+
+var getAttachment = require('../../helpers/unit').unit([
+ 'attachment',
+ 'get'
+]);
+
+getAttachment('airplane-design', 'wings.pdf', {rev: 'rev-3'}, {
+ encoding: null,
+ headers: {},
+ method: 'GET',
+ qs: {rev: 'rev-3'},
+ uri: '/mock/airplane-design/wings.pdf'
+});
+
+getAttachment('airplane-design', 'wings.pdf', {
+ encoding: null,
+ headers: {},
+ method: 'GET',
+ uri: '/mock/airplane-design/wings.pdf'
+});
diff --git a/tests/unit/attachment/insert.js b/tests/unit/attachment/insert.js
new file mode 100644
index 0000000..c30870e
--- /dev/null
+++ b/tests/unit/attachment/insert.js
@@ -0,0 +1,34 @@
+'use strict';
+
+var helpers = require('../../helpers/unit');
+var insertAttachment = helpers.unit(['attachment', 'insert']);
+
+var buffer = new Buffer(helpers.pixel, 'base64');
+
+insertAttachment('pixels', 'pixel.bmp', buffer, 'image/bmp', {
+ body: buffer,
+ headers: {
+ 'content-type': 'image/bmp'
+ },
+ method: 'PUT',
+ uri: '/mock/pixels/pixel.bmp'
+});
+
+insertAttachment('pixels', 'meta.txt', 'brown', 'text/plain', {
+ body: 'brown',
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ method: 'PUT',
+ uri: '/mock/pixels/meta.txt'
+});
+
+insertAttachment('pixels', 'meta.txt', 'white', 'text/plain', {rev: '2'}, {
+ body: 'white',
+ headers: {
+ 'content-type': 'text/plain'
+ },
+ method: 'PUT',
+ uri: '/mock/pixels/meta.txt',
+ qs: {rev: '2'}
+});
diff --git a/tests/unit/database/changes.js b/tests/unit/database/changes.js
new file mode 100644
index 0000000..75e2bca
--- /dev/null
+++ b/tests/unit/database/changes.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var changesDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'changes'
+]);
+
+changesDatabase('mock', {since: '10'}, {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ qs: {since: '10'},
+ uri: '/mock/_changes'
+});
+
+changesDatabase('mock', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ uri: '/mock/_changes'
+});
diff --git a/tests/unit/database/compact.js b/tests/unit/database/compact.js
new file mode 100644
index 0000000..14688c3
--- /dev/null
+++ b/tests/unit/database/compact.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var compactDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'compact'
+]);
+
+compactDatabase('mock', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ uri: '/mock/_compact'
+});
diff --git a/tests/unit/database/create.js b/tests/unit/database/create.js
new file mode 100644
index 0000000..b238956
--- /dev/null
+++ b/tests/unit/database/create.js
@@ -0,0 +1,24 @@
+'use strict';
+
+var createDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'create'
+]);
+
+createDatabase('mock', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'PUT',
+ uri: '/mock'
+});
+
+createDatabase('az09_$()+-/', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'PUT',
+ uri: '/az09_%24()%2B-%2F'
+});
diff --git a/tests/unit/database/destroy.js b/tests/unit/database/destroy.js
new file mode 100644
index 0000000..9ba02b1
--- /dev/null
+++ b/tests/unit/database/destroy.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var destroyDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'destroy'
+]);
+
+destroyDatabase('mock', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'DELETE',
+ uri: '/mock'
+});
diff --git a/tests/unit/database/follow.js b/tests/unit/database/follow.js
new file mode 100644
index 0000000..73a18c8
--- /dev/null
+++ b/tests/unit/database/follow.js
@@ -0,0 +1,8 @@
+'use strict';
+
+var followDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'follow'
+]);
+
+followDatabase('space', {db: '/space'});
diff --git a/tests/unit/database/get.js b/tests/unit/database/get.js
new file mode 100644
index 0000000..3faa1df
--- /dev/null
+++ b/tests/unit/database/get.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var getDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'get'
+]);
+
+getDatabase('space', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ uri: '/space'
+});
diff --git a/tests/unit/database/list.js b/tests/unit/database/list.js
new file mode 100644
index 0000000..1579d00
--- /dev/null
+++ b/tests/unit/database/list.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var listDatabases = require('../../helpers/unit').unit([
+ 'database',
+ 'list'
+]);
+
+listDatabases({
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ uri: '/_all_dbs'
+});
diff --git a/tests/unit/database/replicate.js b/tests/unit/database/replicate.js
new file mode 100644
index 0000000..87c3196
--- /dev/null
+++ b/tests/unit/database/replicate.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var replicateDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'replicate'
+]);
+
+replicateDatabase('baa', 'baashep', {
+ body: '{"source":"baa","target":"baashep"}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ uri: '/_replicate'
+});
+
+replicateDatabase('molly', 'anne', {some: 'params'}, {
+ body: '{"some":"params","source":"molly","target":"anne"}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ uri: '/_replicate'
+});
diff --git a/tests/unit/database/updates.js b/tests/unit/database/updates.js
new file mode 100644
index 0000000..f5bb3e1
--- /dev/null
+++ b/tests/unit/database/updates.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var updatesDatabase = require('../../helpers/unit').unit([
+ 'database',
+ 'updates'
+]);
+
+updatesDatabase({
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ uri: '/_db_updates'
+});
+
+updatesDatabase({since: 1}, {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ qs: {since: 1},
+ uri: '/_db_updates'
+});
diff --git a/tests/unit/design/atomic.js b/tests/unit/design/atomic.js
new file mode 100644
index 0000000..0829314
--- /dev/null
+++ b/tests/unit/design/atomic.js
@@ -0,0 +1,19 @@
+'use strict';
+
+var atomicDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'atomic'
+]);
+
+atomicDesign('update', 'inplace', 'foobar', {
+ field: 'foo',
+ value: 'bar'
+ }, {
+ body: '{"field":"foo","value":"bar"}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'PUT',
+ uri: '/mock/_design/update/_update/inplace/foobar'
+});
diff --git a/tests/unit/design/compact.js b/tests/unit/design/compact.js
new file mode 100644
index 0000000..cbb3c9b
--- /dev/null
+++ b/tests/unit/design/compact.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var compactDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'compact'
+]);
+
+compactDesign('alice', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ uri: '/mock/_compact/alice'
+});
diff --git a/tests/unit/design/list.js b/tests/unit/design/list.js
new file mode 100644
index 0000000..e48ece7
--- /dev/null
+++ b/tests/unit/design/list.js
@@ -0,0 +1,23 @@
+'use strict';
+
+var listDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'viewWithList'
+]);
+
+listDesign('people', 'by_name_and_city', 'my_list', {
+ key: [
+ 'Derek',
+ 'San Francisco'
+ ]
+ }, {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ qs: {
+ 'key': '["Derek","San Francisco"]'
+ },
+ uri: '/mock/_design/people/_list/my_list/by_name_and_city'
+});
diff --git a/tests/unit/design/search.js b/tests/unit/design/search.js
new file mode 100644
index 0000000..977577f
--- /dev/null
+++ b/tests/unit/design/search.js
@@ -0,0 +1,18 @@
+'use strict';
+
+var searchDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'search'
+]);
+
+searchDesign('alice', 'by_id', {
+ keys: 'dawg'
+}, {
+ body: '{"keys":"dawg"}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ uri: '/mock/_design/alice/_search/by_id'
+});
diff --git a/tests/unit/design/show.js b/tests/unit/design/show.js
new file mode 100644
index 0000000..c184865
--- /dev/null
+++ b/tests/unit/design/show.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var showDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'show'
+]);
+
+showDesign('people', 'singleDoc', 'p_clemens', {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ uri: '/mock/_design/people/_show/singleDoc/p_clemens'
+});
diff --git a/tests/unit/design/spatial.js b/tests/unit/design/spatial.js
new file mode 100644
index 0000000..7e5810b
--- /dev/null
+++ b/tests/unit/design/spatial.js
@@ -0,0 +1,16 @@
+'use strict';
+
+var geoDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'spatial'
+]);
+
+geoDesign('people', 'byArea', {x: '1'}, {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'GET',
+ qs: {x: '1'},
+ uri: '/mock/_design/people/_spatial/byArea'
+});
diff --git a/tests/unit/design/view.js b/tests/unit/design/view.js
new file mode 100644
index 0000000..1f80a63
--- /dev/null
+++ b/tests/unit/design/view.js
@@ -0,0 +1,22 @@
+'use strict';
+
+var viewDesign = require('../../helpers/unit').unit([
+ 'view',
+ 'view'
+]);
+
+viewDesign('alice', 'by_id', {
+ keys: ['foobar', 'barfoo'],
+ 'include_docs': true
+}, {
+ body: '{"keys":["foobar","barfoo"]}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ qs: {
+ 'include_docs': true
+ },
+ uri: '/mock/_design/alice/_view/by_id'
+});
diff --git a/tests/unit/document/bulk.js b/tests/unit/document/bulk.js
new file mode 100644
index 0000000..6727a48
--- /dev/null
+++ b/tests/unit/document/bulk.js
@@ -0,0 +1,34 @@
+'use strict';
+
+var bulkDocument = require('../../helpers/unit').unit([
+ 'document',
+ 'bulk'
+]);
+
+bulkDocument({
+ docs: [
+ {key: 'baz', name: 'bazzel'},
+ {key: 'bar', name: 'barry'}
+ ]
+}, {
+ body: '{"docs":[{"key":"baz","name":"bazzel"},{"key":"bar","name":"barry"}]}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ uri: '/mock/_bulk_docs'
+});
+
+bulkDocument({
+ docs: []
+}, {wat: 'izlove'}, {
+ body: '{"docs":[]}',
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'POST',
+ qs: {wat: 'izlove'},
+ uri: '/mock/_bulk_docs'
+});
diff --git a/tests/unit/document/copy.js b/tests/unit/document/copy.js
new file mode 100644
index 0000000..822cefc
--- /dev/null
+++ b/tests/unit/document/copy.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var copyDocument = require('../../helpers/unit').unit([
+ 'document',
+ 'copy'
+]);
+
+var copyDocumentFail = require('../../helpers/unit').unit([
+ 'document',
+ 'copy'
+], new Error('OMG This sucks'));
+
+copyDocument('excel', 'numbers', {
+ headers: {
+ 'Destination': 'numbers',
+ 'accept': 'application/json',
+ 'content-type': 'application/json'
+ },
+ method: 'COPY',
+ uri: '/mock/excel'
+});
+
+copyDocumentFail('excel', 'numbers', {overwrite: 'yes'}, {
+
+});
diff --git a/tests/unit/multipart/get.js b/tests/unit/multipart/get.js
new file mode 100644
index 0000000..68d2c51
--- /dev/null
+++ b/tests/unit/multipart/get.js
@@ -0,0 +1,14 @@
+'use strict';
+
+var getMultipart = require('../../helpers/unit').unit([
+ 'multipart',
+ 'get'
+]);
+
+getMultipart('space', {extra: 'stuff'}, {
+ encoding: null,
+ headers: {'content-type': 'multipart/related'},
+ method: 'GET',
+ qs: {attachments: true, extra: 'stuff'},
+ uri: '/mock/space'
+});
diff --git a/tests/unit/multipart/insert.js b/tests/unit/multipart/insert.js
new file mode 100644
index 0000000..be197bf
--- /dev/null
+++ b/tests/unit/multipart/insert.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var insertMultipart = require('../../helpers/unit').unit([
+ 'multipart',
+ 'insert'
+]);
+
+insertMultipart({hey: 1}, [{
+ name: 'att',
+ data: 'some',
+ 'content_type': 'text/plain'
+ }], {extra: 'stuff'}, {
+ headers: {
+ 'content-type': 'multipart/related'
+ },
+ method: 'PUT',
+ multipart: [
+ {
+ body: '{"_attachments":{"att":{"follows":true,"length":4}},"hey":1}',
+ 'content-type': 'application/json'
+ },
+ {body: 'some'}
+ ],
+ qs: {extra: 'stuff'},
+ uri: '/mock'
+});
diff --git a/tests/unit/shared/error.js b/tests/unit/shared/error.js
new file mode 100644
index 0000000..67d7eeb
--- /dev/null
+++ b/tests/unit/shared/error.js
@@ -0,0 +1,45 @@
+'use strict';
+
+var helpers = require('../../helpers/unit');
+var test = require('tape');
+var debug = require('debug')('nano/tests/unit/shared/error');
+
+var cli = helpers.mockClientFail(debug);
+var cli2 = helpers.mockClientUnparsedError(debug);
+var cli3 = helpers.mockClientUnparsedError(debug, JSON.stringify({
+ error: 'not a reason'
+}));
+
+var cli4 = helpers.mockClientUnparsedError(debug, JSON.stringify({
+ stack: new Error('foo').stack
+}));
+
+test('it should be able to set a jar box', function(assert) {
+ cli.relax({}, function(err) {
+ assert.equal(err.message, 'error happened in your connection');
+ assert.end();
+ });
+});
+
+test('should be able to deal with html errors bad couches', function(assert) {
+ cli2.relax({}, function(err) {
+ assert.equal(err.message, '<b> Error happened </b>');
+ assert.end();
+ });
+});
+
+test('should be capable of using `error`', function(assert) {
+ cli3.relax({}, function(err) {
+ assert.equal(err.message, 'not a reason');
+ assert.end();
+ });
+});
+
+test('should remove cloudant stacktraces', function(assert) {
+ cli4.relax({}, function(err) {
+ var msg = err.stack.split('\n')[0];
+ assert.notEqual(msg, 'Error: foo');
+ assert.equal(msg, 'Error: Unspecified error');
+ assert.end();
+ });
+});
diff --git a/tests/unit/shared/follow-updates.js b/tests/unit/shared/follow-updates.js
new file mode 100644
index 0000000..e48a002
--- /dev/null
+++ b/tests/unit/shared/follow-updates.js
@@ -0,0 +1,9 @@
+'use strict';
+
+var followUpdates = require('../../helpers/unit').unit([
+ 'server',
+ 'followUpdates'
+]);
+
+followUpdates({db: '/_db_updates'});
+followUpdates({since: 1}, {db: '/_db_updates', since: 1});
diff --git a/tests/unit/shared/jar.js b/tests/unit/shared/jar.js
new file mode 100644
index 0000000..affd9aa
--- /dev/null
+++ b/tests/unit/shared/jar.js
@@ -0,0 +1,18 @@
+'use strict';
+
+var helpers = require('../../helpers/unit');
+var test = require('tape');
+var debug = require('debug')('nano/tests/unit/shared/jar');
+
+var cli = helpers.mockClientJar(debug);
+
+test('it should be able to set a jar box', function(assert) {
+ assert.equal(cli.config.jar, 'is set');
+ cli.relax({}, function(_, req) {
+ assert.equal(req.jar, 'is set');
+ cli.relax({jar: 'changed'}, function(_, req) {
+ assert.equal(req.jar, 'changed');
+ assert.end();
+ });
+ });
+});