You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by gl...@apache.org on 2020/02/12 11:25:54 UTC
[couchdb-nano] 06/15: document tests complete
This is an automated email from the ASF dual-hosted git repository.
glynnbird pushed a commit to branch jest
in repository https://gitbox.apache.org/repos/asf/couchdb-nano.git
commit 286db832c8c0ad96b74ac08e940e7abf26a8ed37
Author: Glynn Bird <gl...@gmail.com>
AuthorDate: Thu Feb 6 15:48:41 2020 +0000
document tests complete
---
lib/nano.js | 56 ++++++++--
test/database.listAsStream.test.js | 2 +-
test/document.bulk.test.js | 52 ++++++++++
test/document.copy.test.js | 76 ++++++++++++++
test/document.destroy.test.js | 51 ++++++++++
test/document.fetch.test.js | 160 +++++++++++++++++++++++++++++
test/document.fetchRevs.test.js | 124 ++++++++++++++++++++++
test/document.get.test.js | 65 ++++++++++++
test/document.head.test.js | 66 ++++++++++++
test/document.insert.test.js | 128 +++++++++++++++++++++++
test/document.list.test.js | 104 +++++++++++++++++++
test/document.listAsStream.test.js | 108 ++++++++++++++++++++
test/nano.request.test.js | 204 ++++++++++++++++++++++++++++++++++---
13 files changed, 1174 insertions(+), 22 deletions(-)
diff --git a/lib/nano.js b/lib/nano.js
index 6e6e535..7b63bc3 100644
--- a/lib/nano.js
+++ b/lib/nano.js
@@ -519,11 +519,11 @@ module.exports = exports = function dbScope (cfg) {
// http://docs.couchdb.org/en/latest/api/document/common.html#delete--db-docid
function destroyDoc (docName, rev, callback) {
if (!docName) {
- const msg = 'Invalid doc id'
+ const e = new Error('Invalid doc id')
if (callback) {
- callback(msg, null)
+ return callback(e, null)
} else {
- return Promise.reject(msg)
+ return Promise.reject(e)
}
} else {
return relax({
@@ -540,7 +540,12 @@ module.exports = exports = function dbScope (cfg) {
const { opts, callback } = getCallback(qs0, callback0)
if (!docName) {
- if (callback) { callback(new Error('Invalid doc id'), null) }
+ const e = new Error('Invalid doc id')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
} else {
return relax({ db: dbName, doc: docName, qs: opts }, callback)
}
@@ -548,6 +553,14 @@ module.exports = exports = function dbScope (cfg) {
// http://docs.couchdb.org/en/latest/api/document/common.html#head--db-docid
function headDoc (docName, callback) {
+ if (!docName) {
+ const e = new Error('Invalid doc id')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
if (callback) {
relax({
db: dbName,
@@ -579,6 +592,15 @@ module.exports = exports = function dbScope (cfg) {
function copyDoc (docSrc, docDest, opts0, callback0) {
const { opts, callback } = getCallback(opts0, callback0)
+ if (!docSrc || !docDest) {
+ const e = new Error('Invalid doc id')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
+
const qs = {
db: dbName,
doc: docSrc,
@@ -593,7 +615,7 @@ module.exports = exports = function dbScope (cfg) {
qs.headers.Destination += '?rev=' +
h.etag.substring(1, h.etag.length - 1)
}
- relax(qs, callback)
+ return relax(qs, callback)
},
function (e) {
if (e && e.statusCode !== 404) {
@@ -603,7 +625,7 @@ module.exports = exports = function dbScope (cfg) {
return Promise.reject(e)
}
} else {
- relax(qs, callback)
+ return relax(qs, callback)
}
}
)
@@ -631,6 +653,17 @@ module.exports = exports = function dbScope (cfg) {
const { opts, callback } = getCallback(qs0, callback0)
opts.include_docs = true
+ if (!docNames || typeof docNames !== 'object' ||
+ !docNames.keys || !Array.isArray(docNames.keys) ||
+ docNames.keys.length === 0) {
+ const e = new Error('Invalid keys')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
+
return relax({
db: dbName,
path: '_all_docs',
@@ -642,6 +675,17 @@ module.exports = exports = function dbScope (cfg) {
function fetchRevs (docNames, qs0, callback0) {
const { opts, callback } = getCallback(qs0, callback0)
+
+ if (!docNames || typeof docNames !== 'object' ||
+ !docNames.keys || !Array.isArray(docNames.keys) ||
+ docNames.keys.length === 0) {
+ const e = new Error('Invalid keys')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
return relax({
db: dbName,
path: '_all_docs',
diff --git a/test/database.listAsStream.test.js b/test/database.listAsStream.test.js
index 6568e26..25b6ed2 100644
--- a/test/database.listAsStream.test.js
+++ b/test/database.listAsStream.test.js
@@ -23,7 +23,7 @@ test('should get a streamed list of databases - GET /_all_dbs - nano.db.listAsSt
.reply(200, response)
return new Promise((resolve, reject) => {
- // test GET /db/_all_dbs
+ // test GET /_all_dbs
const s = nano.db.listAsStream()
expect(typeof s).toBe('object')
let buffer = ''
diff --git a/test/document.bulk.test.js b/test/document.bulk.test.js
new file mode 100644
index 0000000..672df9d
--- /dev/null
+++ b/test/document.bulk.test.js
@@ -0,0 +1,52 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to insert documents in bulk - POST /db/_bulk_docs - db.bulk', async () => {
+ // mocks
+ const docs = [{ a: 1, b: 2 }, { a: 2, b: 3 }, { a: 3, b: 4 }]
+ const response = [
+ { ok: true, id: 'x', rev: '1-123' },
+ { ok: true, id: 'y', rev: '1-456' },
+ { ok: true, id: 'z', rev: '1-789' }
+ ]
+ const scope = nock(COUCH_URL)
+ .post('/db/_bulk_docs', { docs: docs })
+ .reply(200, response)
+
+ // test POST /db/_bulk_docs
+ const db = nano.db.use('db')
+ const p = await db.bulk({ docs: docs })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle missing database - POST /db/_bulk_docs - db.bulk', async () => {
+ // mocks
+ const docs = [{ a: 1, b: 2 }, { a: 2, b: 3 }, { a: 3, b: 4 }]
+ const response = {
+ error: 'not_found',
+ reason: 'Database does not exist.'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_bulk_docs', { docs: docs })
+ .reply(404, response)
+
+ // test POST /db/_bulk_docs
+ const db = nano.db.use('db')
+ await expect(db.bulk({ docs: docs })).rejects.toThrow('Database does not exist.')
+ expect(scope.isDone()).toBe(true)
+})
diff --git a/test/document.copy.test.js b/test/document.copy.test.js
new file mode 100644
index 0000000..29d2d6a
--- /dev/null
+++ b/test/document.copy.test.js
@@ -0,0 +1,76 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to copy a document - db.copy', async () => {
+ // mocks
+ const response = { ok: true, id: 'rabbit2', rev: '1-123' }
+ const scope = nock(COUCH_URL, { reqheaders: { destination: 'rabbit2' } })
+ .intercept('/db/rabbit1', 'COPY')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.copy('rabbit1', 'rabbit2')
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing source doc id - db.copy', async () => {
+ const db = nano.db.use('db')
+ await expect(db.copy(undefined, 'rabbbit2')).rejects.toThrow('Invalid doc id')
+})
+
+test('should detect missing target doc id - db.copy', async () => {
+ const db = nano.db.use('db')
+ await expect(db.copy('rabbit1')).rejects.toThrow('Invalid doc id')
+})
+
+test('should be able to copy a document in overwrite mode - db.copy', async () => {
+ // mocks
+ const response = { ok: true, id: 'rabbit2', rev: '1-123' }
+ const scope = nock(COUCH_URL)
+ .head('/db/rabbit2')
+ .reply(200, '', { ETag: '1-123' })
+ .intercept('/db/rabbit1', 'COPY')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.copy('rabbit1', 'rabbit2', { overwrite: true })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to copy a document in overwrite mode missing target - db.copy', async () => {
+ // mocks
+ const response = { ok: true, id: 'rabbit2', rev: '1-123' }
+ const errResponse = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .head('/db/rabbit2')
+ .reply(404, errResponse)
+ .intercept('/db/rabbit1', 'COPY')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.copy('rabbit1', 'rabbit2', { overwrite: true })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
diff --git a/test/document.destroy.test.js b/test/document.destroy.test.js
new file mode 100644
index 0000000..2177992
--- /dev/null
+++ b/test/document.destroy.test.js
@@ -0,0 +1,51 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to destroy a document - DELETE /db/id - db.destroy', async () => {
+ // mocks
+ const response = { ok: true, id: 'id', rev: '2-456' }
+ const scope = nock(COUCH_URL)
+ .delete('/db/id?rev=1-123')
+ .reply(200, response)
+
+ // test DELETE /db/id
+ const db = nano.db.use('db')
+ const p = await db.destroy('id', '1-123')
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 409 conflicts - DELETE /db/id - db.destroy', async () => {
+ // mocks
+ const response = {
+ error: 'conflict',
+ reason: 'Document update conflict.'
+ }
+ const scope = nock(COUCH_URL)
+ .delete('/db/id?rev=1-123')
+ .reply(409, response)
+
+ // test DELETE /db/id
+ const db = nano.db.use('db')
+ await expect(db.destroy('id', '1-123')).rejects.toThrow('Document update conflict.')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing doc id - db.destroy', async () => {
+ const db = nano.db.use('db')
+ await expect(db.destroy(undefined, '1-123')).rejects.toThrow('Invalid doc id')
+})
diff --git a/test/document.fetch.test.js b/test/document.fetch.test.js
new file mode 100644
index 0000000..55281fc
--- /dev/null
+++ b/test/document.fetch.test.js
@@ -0,0 +1,160 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to fetch a list of documents - POST /db/_all_docs - db.fetch', async () => {
+ // mocks
+ const keys = ['1000501', '1000543', '100077']
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ },
+ doc: {
+ _id: '1000501',
+ _rev: '2-46dcf6bf2f8d428504f5290e591aa182',
+ a: 1,
+ b: 2
+ }
+ },
+ {
+ id: '1000543',
+ key: '1000543',
+ value: {
+ rev: '1-3256046064953e2f0fdb376211fe78ab'
+ },
+ doc: {
+ _id: '1000543',
+ _rev: '2-3256046064953e2f0fdb376211fe78ab',
+ a: 3,
+ b: 4
+ }
+ },
+ {
+ id: '100077',
+ key: '100077',
+ value: {
+ rev: '1-101bff1251d4bd75beb6d3c232d05a5c'
+ },
+ doc: {
+ _id: '100077',
+ _rev: '2-101bff1251d4bd75beb6d3c232d05a5c',
+ a: 5,
+ b: 6
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_all_docs?include_docs=true', { keys: keys })
+ .reply(200, response)
+
+ // test POST /db/_all_docs
+ const db = nano.db.use('db')
+ const p = await db.fetch({ keys: keys })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to fetch a list of documents with opts - GET /db/_all_docs - db.fetch', async () => {
+ // mocks
+ const keys = ['1000501', '1000543', '100077']
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ },
+ doc: {
+ _id: '1000501',
+ _rev: '2-46dcf6bf2f8d428504f5290e591aa182',
+ a: 1,
+ b: 2
+ }
+ },
+ {
+ id: '1000543',
+ key: '1000543',
+ value: {
+ rev: '1-3256046064953e2f0fdb376211fe78ab'
+ },
+ doc: {
+ _id: '1000543',
+ _rev: '2-3256046064953e2f0fdb376211fe78ab',
+ a: 3,
+ b: 4
+ }
+ },
+ {
+ id: '100077',
+ key: '100077',
+ value: {
+ rev: '1-101bff1251d4bd75beb6d3c232d05a5c'
+ },
+ doc: {
+ _id: '100077',
+ _rev: '2-101bff1251d4bd75beb6d3c232d05a5c',
+ a: 5,
+ b: 6
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_all_docs?include_docs=true&descending=true', { keys: keys })
+ .reply(200, response)
+
+ // test POST /db/_all_docs
+ const db = nano.db.use('db')
+ const p = await db.fetch({ keys: keys }, { descending: true })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - POST /db/_all_docs - db.fetch', async () => {
+ // mocks
+ const keys = ['1000501', '1000543', '100077']
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_all_docs?include_docs=true', { keys: keys })
+ .reply(404, response)
+
+ // test POST /db/_all_docs
+ const db = nano.db.use('db')
+ await expect(db.fetch({ keys: keys })).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing keys - db.fetch', async () => {
+ const db = nano.db.use('db')
+ await expect(db.fetch()).rejects.toThrow('Invalid keys')
+ await expect(db.fetch({})).rejects.toThrow('Invalid keys')
+ await expect(db.fetch({ keys: {} })).rejects.toThrow('Invalid keys')
+ await expect(db.fetch({ keys: '123' })).rejects.toThrow('Invalid keys')
+ await expect(db.fetch({ keys: [] })).rejects.toThrow('Invalid keys')
+})
diff --git a/test/document.fetchRevs.test.js b/test/document.fetchRevs.test.js
new file mode 100644
index 0000000..80eda1c
--- /dev/null
+++ b/test/document.fetchRevs.test.js
@@ -0,0 +1,124 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to fetch a list of document revisions - POST /db/_all_docs - db.fetch', async () => {
+ // mocks
+ const keys = ['1000501', '1000543', '100077']
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ }
+ },
+ {
+ id: '1000543',
+ key: '1000543',
+ value: {
+ rev: '1-3256046064953e2f0fdb376211fe78ab'
+ }
+ },
+ {
+ id: '100077',
+ key: '100077',
+ value: {
+ rev: '1-101bff1251d4bd75beb6d3c232d05a5c'
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_all_docs', { keys: keys })
+ .reply(200, response)
+
+ // test POST /db/_all_docs
+ const db = nano.db.use('db')
+ const p = await db.fetchRevs({ keys: keys })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to fetch a list of document revisions with opts - GET /db/_all_docs - db.fetch', async () => {
+ // mocks
+ const keys = ['1000501', '1000543', '100077']
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ }
+ },
+ {
+ id: '1000543',
+ key: '1000543',
+ value: {
+ rev: '1-3256046064953e2f0fdb376211fe78ab'
+ }
+ },
+ {
+ id: '100077',
+ key: '100077',
+ value: {
+ rev: '1-101bff1251d4bd75beb6d3c232d05a5c'
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_all_docs?descending=true', { keys: keys })
+ .reply(200, response)
+
+ // test POST /db/_all_docs
+ const db = nano.db.use('db')
+ const p = await db.fetchRevs({ keys: keys }, { descending: true })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - POST /db/_all_docs - db.fetch', async () => {
+ // mocks
+ const keys = ['1000501', '1000543', '100077']
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_all_docs', { keys: keys })
+ .reply(404, response)
+
+ // test POST /db/_all_docs
+ const db = nano.db.use('db')
+ await expect(db.fetchRevs({ keys: keys })).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing keys - db.fetch', async () => {
+ const db = nano.db.use('db')
+ await expect(db.fetchRevs()).rejects.toThrow('Invalid keys')
+ await expect(db.fetchRevs({})).rejects.toThrow('Invalid keys')
+ await expect(db.fetchRevs({ keys: {} })).rejects.toThrow('Invalid keys')
+ await expect(db.fetchRevs({ keys: '123' })).rejects.toThrow('Invalid keys')
+ await expect(db.fetchRevs({ keys: [] })).rejects.toThrow('Invalid keys')
+})
diff --git a/test/document.get.test.js b/test/document.get.test.js
new file mode 100644
index 0000000..a2cfcca
--- /dev/null
+++ b/test/document.get.test.js
@@ -0,0 +1,65 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to get a document - GET /db/id - db.get', async () => {
+ // mocks
+ const response = { _id: 'id', rev: '1-123', a: 1, b: 'two', c: true }
+ const scope = nock(COUCH_URL)
+ .get('/db/id')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.get('id')
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to get a document with options - GET /db/id?conflicts=true - db.get', async () => {
+ // mocks
+ const response = { _id: 'id', rev: '1-123', a: 1, b: 'two', c: true }
+ const scope = nock(COUCH_URL)
+ .get('/db/id?conflicts=true')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.get('id', { conflicts: true })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - GET /db/id - db.get', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/id')
+ .reply(404, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ await expect(db.get('id')).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing doc id - db.get', async () => {
+ const db = nano.db.use('db')
+ await expect(db.get()).rejects.toThrow('Invalid doc id')
+})
diff --git a/test/document.head.test.js b/test/document.head.test.js
new file mode 100644
index 0000000..dc2cb99
--- /dev/null
+++ b/test/document.head.test.js
@@ -0,0 +1,66 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to head a document - HEAD /db/id - db.head', async () => {
+ // mocks
+ const scope = nock(COUCH_URL)
+ .head('/db/id')
+ .reply(200, '', { ETag: '1-123' })
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.head('id')
+ // headers get lowercased
+ expect(p.etag).toBe('1-123')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to head a document with callback - HEAD /db/id - db.head', async () => {
+ // mocks
+ const scope = nock(COUCH_URL)
+ .head('/db/id')
+ .reply(200, '', { ETag: '1-123' })
+
+ // test GET /db
+ return new Promise((resolve, reject) => {
+ const db = nano.db.use('db')
+ db.head('id', (err, data, headers) => {
+ // headers get lowercased
+ expect(err).toBeNull()
+ expect(headers.etag).toBe('1-123')
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
+
+test('should be able to head a missing document - HEAD /db/id - db.head', async () => {
+ // mocks
+ const scope = nock(COUCH_URL)
+ .head('/db/id')
+ .reply(404, '')
+
+ // test GET /db
+ const db = nano.db.use('db')
+ await expect(db.head('id')).rejects.toThrow('couch returned 404')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing doc id - db.head', async () => {
+ const db = nano.db.use('db')
+ await expect(db.head()).rejects.toThrow('Invalid doc id')
+})
diff --git a/test/document.insert.test.js b/test/document.insert.test.js
new file mode 100644
index 0000000..812775b
--- /dev/null
+++ b/test/document.insert.test.js
@@ -0,0 +1,128 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to insert document - POST /db - db.insert', async () => {
+ // mocks
+ const doc = { a: 1, b: 2 }
+ const response = { ok: true, id: '8s8g8h8h9', rev: '1-123' }
+ const scope = nock(COUCH_URL)
+ .post('/db', doc)
+ .reply(200, response)
+
+ // test POST /db
+ const db = nano.db.use('db')
+ const p = await db.insert(doc)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to insert document with opts - POST /db?batch=ok - db.insert', async () => {
+ // mocks
+ const doc = { a: 1, b: 2 }
+ const response = { ok: true, id: '8s8g8h8h9', rev: '1-123' }
+ const scope = nock(COUCH_URL)
+ .post('/db?batch=ok', doc)
+ .reply(200, response)
+
+ // test POST /db
+ const db = nano.db.use('db')
+ const p = await db.insert(doc, { batch: 'ok' })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to insert document with known id - PUT /db/id - db.insert', async () => {
+ // mocks
+ const doc = { a: 1, b: 2 }
+ const response = { ok: true, id: 'myid', rev: '1-123' }
+
+ const scope = nock(COUCH_URL)
+ .put('/db/myid', doc)
+ .reply(200, response)
+
+ // test PUT /db
+ const db = nano.db.use('db')
+ const p = await db.insert(doc, 'myid')
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to insert document with id in object - POST /db - db.insert', async () => {
+ // mocks
+ const doc = { _id: 'myid', a: 1, b: 2 }
+ const response = { ok: true, id: 'myid', rev: '1-123' }
+
+ const scope = nock(COUCH_URL)
+ .post('/db', doc)
+ .reply(200, response)
+
+ // test POST /db
+ const db = nano.db.use('db')
+ const p = await db.insert(doc)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to update document with id/rev in object - POST /db - db.insert', async () => {
+ // mocks
+ const doc = { _id: 'myid', _rev: '1-123', a: 2, b: 2 }
+ const response = { ok: true, id: 'myid', rev: '2-456' }
+
+ const scope = nock(COUCH_URL)
+ .post('/db', doc)
+ .reply(200, response)
+
+ // test POST /db
+ const db = nano.db.use('db')
+ const p = await db.insert(doc)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 409 conflicts - POST /db - db.insert', async () => {
+ // mocks
+ const doc = { _id: 'myid', _rev: '1-123', a: 2, b: 2 }
+ const response = {
+ error: 'conflict',
+ reason: 'Document update conflict.'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db', doc)
+ .reply(409, response)
+
+ // test POST /db
+ const db = nano.db.use('db')
+ await expect(db.insert(doc)).rejects.toThrow('Document update conflict.')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle missing database - POST /db - db.insert', async () => {
+ // mocks
+ const doc = { a: 1, b: 2 }
+ const response = {
+ error: 'not_found',
+ reason: 'Database does not exist.'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db', doc)
+ .reply(404, response)
+
+ // test POST /db
+ const db = nano.db.use('db')
+ await expect(db.insert(doc)).rejects.toThrow('Database does not exist.')
+ expect(scope.isDone()).toBe(true)
+})
diff --git a/test/document.list.test.js b/test/document.list.test.js
new file mode 100644
index 0000000..3e0705f
--- /dev/null
+++ b/test/document.list.test.js
@@ -0,0 +1,104 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to get a list of documents - GET /db/_all_docs - db.list', async () => {
+ // mocks
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ }
+ },
+ {
+ id: '1000543',
+ key: '1000543',
+ value: {
+ rev: '1-3256046064953e2f0fdb376211fe78ab'
+ }
+ },
+ {
+ id: '100077',
+ key: '100077',
+ value: {
+ rev: '1-101bff1251d4bd75beb6d3c232d05a5c'
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .reply(200, response)
+
+ // test GET /db/_all_docs
+ const db = nano.db.use('db')
+ const p = await db.list()
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to get a list of documents with opts - GET /db/_all_docs - db.list', async () => {
+ // mocks
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ },
+ doc: {
+ _id: '1000501',
+ _rev: '2-46dcf6bf2f8d428504f5290e591aa182',
+ a: 1,
+ b: 2
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs?include_docs=true&limit=1')
+ .reply(200, response)
+
+ // test GET /db/_all_docs
+ const db = nano.db.use('db')
+ const p = await db.list({ include_docs: true, limit: 1 })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - GET /db/_all_docs - db.list', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .reply(404, response)
+
+ // test GET /db/_all_docs
+ const db = nano.db.use('db')
+ await expect(db.list()).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
diff --git a/test/document.listAsStream.test.js b/test/document.listAsStream.test.js
new file mode 100644
index 0000000..45cdf49
--- /dev/null
+++ b/test/document.listAsStream.test.js
@@ -0,0 +1,108 @@
+// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should get a streamed list of documents - GET /db/_all_docs - db.listAsStream', async () => {
+ // mocks
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ }
+ },
+ {
+ id: '1000543',
+ key: '1000543',
+ value: {
+ rev: '1-3256046064953e2f0fdb376211fe78ab'
+ }
+ },
+ {
+ id: '100077',
+ key: '100077',
+ value: {
+ rev: '1-101bff1251d4bd75beb6d3c232d05a5c'
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .reply(200, response)
+
+ return new Promise((resolve, reject) => {
+ // test GET /db/_all_docs
+ const db = nano.db.use('db')
+ const s = db.listAsStream()
+ expect(typeof s).toBe('object')
+ let buffer = ''
+ s.on('data', (chunk) => {
+ buffer += chunk.toString()
+ })
+ s.on('end', () => {
+ expect(buffer).toBe(JSON.stringify(response))
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
+
+test('should get a streamed list of documents with opts- GET /db/_all_docs - db.listAsStream', async () => {
+ // mocks
+ const response = {
+ total_rows: 23516,
+ offset: 0,
+ rows: [
+ {
+ id: '1000501',
+ key: '1000501',
+ value: {
+ rev: '2-46dcf6bf2f8d428504f5290e591aa182'
+ },
+ doc: {
+ _id: '1000501',
+ _rev: '2-46dcf6bf2f8d428504f5290e591aa182',
+ a: 1,
+ b: 2
+ }
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs?limit=1&include_docs=true')
+ .reply(200, response)
+
+ return new Promise((resolve, reject) => {
+ // test GET /db/_all_docs
+ const db = nano.db.use('db')
+ const s = db.listAsStream({ limit: 1, include_docs: true })
+ expect(typeof s).toBe('object')
+ let buffer = ''
+ s.on('data', (chunk) => {
+ buffer += chunk.toString()
+ })
+ s.on('end', () => {
+ expect(buffer).toBe(JSON.stringify(response))
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
diff --git a/test/nano.request.test.js b/test/nano.request.test.js
index dc23da1..045071d 100644
--- a/test/nano.request.test.js
+++ b/test/nano.request.test.js
@@ -19,13 +19,13 @@ test('check request can do GET requests - nano.request', async () => {
// mocks
const response = { ok: true }
const scope = nock(COUCH_URL)
- .get('/mydb?a=1&b=2')
+ .get('/db?a=1&b=2')
.reply(200, response)
- // test GET /db
+ // test GET /db?a=1&b=2
const req = {
method: 'get',
- db: 'mydb',
+ db: 'db',
qs: { a: 1, b: 2 }
}
const p = await nano.request(req)
@@ -37,13 +37,13 @@ test('check request can do POST requests - nano.request', async () => {
// mocks
const response = { ok: true }
const scope = nock(COUCH_URL)
- .post('/mydb', { _id: '1', a: true })
+ .post('/db', { _id: '1', a: true })
.reply(200, response)
- // test GET /db
+ // test POST /db
const req = {
method: 'post',
- db: 'mydb',
+ db: 'db',
body: { _id: '1', a: true }
}
const p = await nano.request(req)
@@ -55,13 +55,13 @@ test('check request can do PUT requests - nano.request', async () => {
// mocks
const response = { ok: true }
const scope = nock(COUCH_URL)
- .put('/mydb/1', { _id: '1', a: true })
+ .put('/db/1', { _id: '1', a: true })
.reply(200, response)
- // test GET /db
+ // test PUT /db
const req = {
method: 'put',
- db: 'mydb',
+ db: 'db',
path: '1',
body: { _id: '1', a: true }
}
@@ -74,14 +74,14 @@ test('check request can do DELETE requests - nano.request', async () => {
// mocks
const response = { ok: true }
const scope = nock(COUCH_URL)
- .delete('/mydb/mydoc')
+ .delete('/db/mydoc')
.query({ rev: '1-123' })
.reply(200, response)
- // test GET /db
+ // test DELETE /db
const req = {
method: 'delete',
- db: 'mydb',
+ db: 'db',
path: 'mydoc',
qs: { rev: '1-123' }
@@ -95,16 +95,190 @@ test('check request can do HEAD requests - nano.request', async () => {
// mocks
const response = ''
const scope = nock(COUCH_URL)
- .head('/mydb/mydoc')
+ .head('/db/mydoc')
.reply(200, '')
- // test GET /db
+ // test HEAD /db/mydoc
const req = {
method: 'head',
- db: 'mydb',
+ db: 'db',
path: 'mydoc'
}
const p = await nano.request(req)
expect(p).toStrictEqual(response)
expect(scope.isDone()).toBe(true)
})
+
+test('check request can do GET requests with callback - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const scope = nock(COUCH_URL)
+ .get('/db?a=1&b=2')
+ .reply(200, response)
+
+ // test GET /db?a=1&b=2
+ const req = {
+ method: 'get',
+ db: 'db',
+ qs: { a: 1, b: 2 }
+ }
+ return new Promise((resolve, reject) => {
+ nano.request(req, (err, data) => {
+ expect(err).toBe(null)
+ expect(data).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
+
+test('check request can do failed GET requests with callback - nano.request', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/a')
+ .reply(404, response)
+
+ // test GET /db/a
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: 'a'
+ }
+ return new Promise((resolve, reject) => {
+ nano.request(req, (err, data) => {
+ expect(err).not.toBe(null)
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
+
+test('check request formats keys properly - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const arr = ['a', 'b', 'c']
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .query({ keys: JSON.stringify(arr) })
+ .reply(200, response)
+
+ // test GET /db/_all_docs?keys=[]
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: '_all_docs',
+ qs: { keys: arr }
+ }
+ const p = await nano.request(req)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('check request formats startkey properly - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const val = 'x'
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .query({ startkey: JSON.stringify(val) })
+ .reply(200, response)
+
+ // test GET /db/_all_docs?startkey=
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: '_all_docs',
+ qs: { startkey: val }
+ }
+ const p = await nano.request(req)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('check request formats start_key properly - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const val = 'x'
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .query({ start_key: JSON.stringify(val) })
+ .reply(200, response)
+
+ // test GET /db/_all_docs?start_key=
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: '_all_docs',
+ qs: { start_key: val }
+ }
+ const p = await nano.request(req)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('check request formats endkey properly - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const val = 'x'
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .query({ endkey: JSON.stringify(val) })
+ .reply(200, response)
+
+ // test GET /db/_all_docs?endkey=
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: '_all_docs',
+ qs: { endkey: val }
+ }
+ const p = await nano.request(req)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('check request formats end_key properly - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const val = 'x'
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .query({ end_key: JSON.stringify(val) })
+ .reply(200, response)
+
+ // test GET /db/_all_docs?end_key=
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: '_all_docs',
+ qs: { end_key: val }
+ }
+ const p = await nano.request(req)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('check request formats key properly - nano.request', async () => {
+ // mocks
+ const response = { ok: true }
+ const val = 'x'
+ const scope = nock(COUCH_URL)
+ .get('/db/_all_docs')
+ .query({ key: JSON.stringify(val) })
+ .reply(200, response)
+
+ // test GET /db/_all_docs?key=
+ const req = {
+ method: 'get',
+ db: 'db',
+ path: '_all_docs',
+ qs: { key: val }
+ }
+ const p = await nano.request(req)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})