summaryrefslogtreecommitdiffstats
path: root/js/dav/test/unit
diff options
context:
space:
mode:
authorHendrik Leppelsack <hendrik@leppelsack.de>2016-02-18 16:33:26 +0100
committerHendrik Leppelsack <hendrik@leppelsack.de>2016-02-18 16:39:26 +0100
commit43462d3fc447ac8d843e98e9dc596e21302b1353 (patch)
tree7fae6fd90d269d4c101715d5f36bb844ab0f0a06 /js/dav/test/unit
parent5b452bc093ebaca4dd95955bd47417d187968352 (diff)
integrate dav library instead of loading via bower
Diffstat (limited to 'js/dav/test/unit')
-rw-r--r--js/dav/test/unit/camelize_test.js23
-rw-r--r--js/dav/test/unit/client_test.js265
-rw-r--r--js/dav/test/unit/data/address_book_query.xml72
-rw-r--r--js/dav/test/unit/data/calendar_query.xml24
-rw-r--r--js/dav/test/unit/data/current_user_principal.xml13
-rw-r--r--js/dav/test/unit/data/index.js23
-rw-r--r--js/dav/test/unit/data/propfind.xml39
-rw-r--r--js/dav/test/unit/data/sync_collection.xml16
-rw-r--r--js/dav/test/unit/nock_wrapper.js47
-rw-r--r--js/dav/test/unit/parser_test.js66
-rw-r--r--js/dav/test/unit/request/address_book_query_test.js69
-rw-r--r--js/dav/test/unit/request/basic_test.js63
-rw-r--r--js/dav/test/unit/request/calendar_query_test.js107
-rw-r--r--js/dav/test/unit/request/propfind_test.js84
-rw-r--r--js/dav/test/unit/request/sync_collection_test.js65
-rw-r--r--js/dav/test/unit/sandbox_test.js72
-rw-r--r--js/dav/test/unit/template_test.js69
-rw-r--r--js/dav/test/unit/transport_test.js256
-rw-r--r--js/dav/test/unit/xmlhttprequest_test.js81
19 files changed, 1454 insertions, 0 deletions
diff --git a/js/dav/test/unit/camelize_test.js b/js/dav/test/unit/camelize_test.js
new file mode 100644
index 00000000..f956d5e0
--- /dev/null
+++ b/js/dav/test/unit/camelize_test.js
@@ -0,0 +1,23 @@
+import { assert } from 'chai';
+
+import camelize from '../../lib/camelize';
+
+suite('camelize', function() {
+ test('single word', function() {
+ assert.strictEqual(camelize('green'), 'green');
+ });
+
+ test('multiple words', function() {
+ assert.strictEqual(
+ camelize('green-eggs-and-ham', '-'),
+ 'greenEggsAndHam'
+ );
+ });
+
+ test('omit delimiter', function() {
+ assert.strictEqual(
+ camelize('green_eggs_and_ham'),
+ 'greenEggsAndHam'
+ );
+ });
+});
diff --git a/js/dav/test/unit/client_test.js b/js/dav/test/unit/client_test.js
new file mode 100644
index 00000000..dac7f5c9
--- /dev/null
+++ b/js/dav/test/unit/client_test.js
@@ -0,0 +1,265 @@
+import sinon from 'sinon';
+
+import * as dav from '../../lib';
+
+suite('Client', function() {
+ let client, xhr, send;
+
+ setup(function() {
+ xhr = new dav.transport.Basic(
+ new dav.Credentials({
+ username: 'Killer BOB',
+ password: 'blacklodge'
+ })
+ );
+
+ send = sinon.stub(xhr, 'send');
+ client = new dav.Client(xhr, { baseUrl: 'https://mail.mozilla.com' });
+ });
+
+ teardown(function() {
+ send.restore();
+ });
+
+ test('#send', function() {
+ let url = 'https://mail.mozilla.com/';
+ let req = dav.request.basic({
+ method: 'PUT',
+ data: 'BEGIN:VCALENDAR\nEND:VCALENDAR',
+ etag: 'abc123'
+ });
+
+ let sandbox = dav.createSandbox();
+ client.send(req, url, { sandbox: sandbox });
+ sinon.assert.calledWith(send, req, url, { sandbox: sandbox });
+ });
+
+ test('#send with relative url', function() {
+ let req = dav.request.basic({
+ method: 'PUT',
+ data: 'BEGIN:VCALENDAR\nEND:VCALENDAR',
+ etag: 'abc123'
+ });
+
+ client.send(req, '/calendars/123.ics');
+ sinon.assert.calledWith(
+ send,
+ req,
+ 'https://mail.mozilla.com/calendars/123.ics'
+ );
+ });
+
+ suite('accounts', function() {
+ let createAccount;
+
+ setup(function() {
+ createAccount = sinon.stub(client._accounts, 'createAccount');
+ });
+
+ teardown(function() {
+ createAccount.restore();
+ });
+
+ test('createAccount', function() {
+ client.createAccount({ sandbox: {}, server: 'http://dav.example.com' });
+ sinon.assert.calledWith(createAccount, {
+ sandbox: {},
+ server: 'http://dav.example.com',
+ xhr: xhr
+ });
+ });
+ });
+
+ suite('calendars', function() {
+ let createCalendarObject,
+ updateCalendarObject,
+ deleteCalendarObject,
+ syncCalendar,
+ syncCaldavAccount;
+
+ setup(function() {
+ createCalendarObject = sinon.stub(
+ client._calendars,
+ 'createCalendarObject'
+ );
+ updateCalendarObject = sinon.stub(
+ client._calendars,
+ 'updateCalendarObject'
+ );
+ deleteCalendarObject = sinon.stub(
+ client._calendars,
+ 'deleteCalendarObject'
+ );
+ syncCalendar = sinon.stub(client._calendars, 'syncCalendar');
+ syncCaldavAccount = sinon.stub(client._calendars, 'syncCaldavAccount');
+ });
+
+ teardown(function() {
+ createCalendarObject.restore();
+ updateCalendarObject.restore();
+ deleteCalendarObject.restore();
+ syncCalendar.restore();
+ syncCaldavAccount.restore();
+ });
+
+ test('#createCalendarObject', function() {
+ let calendar = new dav.Calendar();
+ client.createCalendarObject(calendar, {
+ data: 'BEGIN:VCALENDAR\nEND:VCALENDAR',
+ filename: 'test.ics'
+ });
+ sinon.assert.calledWith(
+ createCalendarObject,
+ calendar,
+ {
+ data: 'BEGIN:VCALENDAR\nEND:VCALENDAR',
+ filename: 'test.ics',
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#updateCalendarObject', function() {
+ let object = new dav.CalendarObject();
+ client.updateCalendarObject(object);
+ sinon.assert.calledWith(
+ updateCalendarObject,
+ object,
+ {
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#deleteCalendarObject', function() {
+ let object = new dav.CalendarObject();
+ client.deleteCalendarObject(object);
+ sinon.assert.calledWith(
+ deleteCalendarObject,
+ object,
+ {
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#syncCalendar', function() {
+ let calendar = new dav.Calendar();
+ client.syncCalendar(calendar, { syncMethod: 'webdav' });
+ sinon.assert.calledWith(
+ syncCalendar,
+ calendar,
+ {
+ syncMethod: 'webdav',
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#syncCaldavAccount', function() {
+ let account = new dav.Account();
+ client.syncCaldavAccount(account, { syncMethod: 'webdav' });
+ sinon.assert.calledWith(
+ syncCaldavAccount,
+ account,
+ {
+ syncMethod: 'webdav',
+ xhr: xhr
+ }
+ );
+ });
+ });
+
+ suite('contacts', function() {
+ let createCard,
+ updateCard,
+ deleteCard,
+ syncAddressBook,
+ syncCarddavAccount;
+
+ setup(function() {
+ createCard = sinon.stub(client._contacts, 'createCard');
+ updateCard = sinon.stub(client._contacts, 'updateCard');
+ deleteCard = sinon.stub(client._contacts, 'deleteCard');
+ syncAddressBook = sinon.stub(client._contacts, 'syncAddressBook');
+ syncCarddavAccount = sinon.stub(client._contacts, 'syncCarddavAccount');
+ });
+
+ teardown(function() {
+ createCard.restore();
+ updateCard.restore();
+ deleteCard.restore();
+ syncAddressBook.restore();
+ syncCarddavAccount.restore();
+ });
+
+ test('#createCard', function() {
+ let addressBook = new dav.AddressBook();
+ client.createCard(addressBook, {
+ data: 'BEGIN:VCARD\nEND:VCARD',
+ filename: 'test.vcf'
+ });
+ sinon.assert.calledWith(
+ createCard,
+ addressBook,
+ {
+ data: 'BEGIN:VCARD\nEND:VCARD',
+ filename: 'test.vcf',
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#updateCard', function() {
+ let object = new dav.VCard();
+ client.updateCard(object);
+ sinon.assert.calledWith(
+ updateCard,
+ object,
+ {
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#deleteCard', function() {
+ let object = new dav.VCard();
+ client.deleteCard(object);
+ sinon.assert.calledWith(
+ deleteCard,
+ object,
+ {
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#syncAddressBook', function() {
+ let addressBook = new dav.AddressBook();
+ client.syncAddressBook(addressBook, {
+ syncMethod: 'basic'
+ });
+ sinon.assert.calledWith(
+ syncAddressBook,
+ addressBook,
+ {
+ syncMethod: 'basic',
+ xhr: xhr
+ }
+ );
+ });
+
+ test('#syncCarddavAccount', function() {
+ let account = new dav.Account();
+ client.syncCarddavAccount(account, { syncMethod: 'basic' });
+ sinon.assert.calledWith(
+ syncCarddavAccount,
+ account,
+ {
+ syncMethod: 'basic',
+ xhr: xhr
+ }
+ );
+ });
+ });
+});
diff --git a/js/dav/test/unit/data/address_book_query.xml b/js/dav/test/unit/data/address_book_query.xml
new file mode 100644
index 00000000..3e7690b7
--- /dev/null
+++ b/js/dav/test/unit/data/address_book_query.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<d:multistatus xmlns:d="DAV:"
+ xmlns:s="http://sabredav.org/ns"
+ xmlns:cal="urn:ietf:params:xml:ns:caldav"
+ xmlns:cs="http://calendarserver.org/ns/"
+ xmlns:card="urn:ietf:params:xml:ns:carddav">
+ <d:response>
+ <d:href>/addressbooks/admin/</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:supported-report-set>
+ <d:supported-report>
+ <d:report>
+ <d:expand-property/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <d:principal-property-search/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <d:principal-search-property-set/>
+ </d:report>
+ </d:supported-report>
+ </d:supported-report-set>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+ <d:response>
+ <d:href>/addressbooks/admin/default/</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:supported-report-set>
+ <d:supported-report>
+ <d:report>
+ <d:expand-property/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <d:principal-property-search/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <d:principal-search-property-set/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <card:addressbook-multiget/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <card:addressbook-query/>
+ </d:report>
+ </d:supported-report>
+ <d:supported-report>
+ <d:report>
+ <d:sync-collection/>
+ </d:report>
+ </d:supported-report>
+ </d:supported-report-set>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+</d:multistatus>
diff --git a/js/dav/test/unit/data/calendar_query.xml b/js/dav/test/unit/data/calendar_query.xml
new file mode 100644
index 00000000..3a276b75
--- /dev/null
+++ b/js/dav/test/unit/data/calendar_query.xml
@@ -0,0 +1,24 @@
+<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
+ <d:response>
+ <d:href>/calendars/johndoe/home/132456762153245.ics</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:getetag>"2134-314"</d:getetag>
+ <c:calendar-data>BEGIN:VCALENDAR
+END:VCALENDAR</c:calendar-data>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+ <d:response>
+ <d:href>/calendars/johndoe/home/132456-34365.ics</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:getetag>"5467-323"</d:getetag>
+ <c:calendar-data>BEGIN:VCALENDAR
+END:VCALENDAR</c:calendar-data>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+</d:multistatus>
diff --git a/js/dav/test/unit/data/current_user_principal.xml b/js/dav/test/unit/data/current_user_principal.xml
new file mode 100644
index 00000000..c1b3ead7
--- /dev/null
+++ b/js/dav/test/unit/data/current_user_principal.xml
@@ -0,0 +1,13 @@
+<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
+ <d:response>
+ <d:href>/</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:current-user-principal>
+ <d:href>/principals/admin%40domain.tld/</d:href>
+ </d:current-user-principal>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+</d:multistatus>
diff --git a/js/dav/test/unit/data/index.js b/js/dav/test/unit/data/index.js
new file mode 100644
index 00000000..627a39b6
--- /dev/null
+++ b/js/dav/test/unit/data/index.js
@@ -0,0 +1,23 @@
+import fs from 'fs';
+import { format } from 'util';
+
+import camelize from '../../../lib/camelize';
+
+let docs = {};
+export default docs;
+
+[
+ 'address_book_query',
+ 'current_user_principal',
+ 'calendar_query',
+ 'propfind',
+ 'sync_collection'
+].forEach(function(responseType) {
+ var camelCase = camelize(responseType);
+ docs[camelCase] = fs
+ .readFileSync(
+ format('%s/%s.xml', __dirname, responseType),
+ 'utf-8'
+ )
+ .replace(/>\s+</g, '><'); // Remove whitespace between close and open tag.
+});
diff --git a/js/dav/test/unit/data/propfind.xml b/js/dav/test/unit/data/propfind.xml
new file mode 100644
index 00000000..274520c7
--- /dev/null
+++ b/js/dav/test/unit/data/propfind.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
+ <d:response>
+ <d:href>/calendars/admin/</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:displayname/>
+ <cs:getctag/>
+ <cal:supported-calendar-component-set/>
+ </d:prop>
+ <d:status>HTTP/1.1 404 Not Found</d:status>
+ </d:propstat>
+ </d:response>
+ <d:response>
+ <d:href>/calendars/admin/default/</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:displayname>default calendar</d:displayname>
+ <cs:getctag>http://sabre.io/ns/sync/0</cs:getctag>
+ <cal:supported-calendar-component-set>
+ <cal:comp name="VEVENT"/>
+ <cal:comp name="VTODO"/>
+ </cal:supported-calendar-component-set>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+ <d:response>
+ <d:href>/calendars/admin/outbox/</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:displayname/>
+ <cs:getctag/>
+ <cal:supported-calendar-component-set/>
+ </d:prop>
+ <d:status>HTTP/1.1 404 Not Found</d:status>
+ </d:propstat>
+ </d:response>
+</d:multistatus>
diff --git a/js/dav/test/unit/data/sync_collection.xml b/js/dav/test/unit/data/sync_collection.xml
new file mode 100644
index 00000000..a2f805ce
--- /dev/null
+++ b/js/dav/test/unit/data/sync_collection.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
+ <d:response>
+ <d:href>/calendars/admin/default/test.ics</d:href>
+ <d:propstat>
+ <d:prop>
+ <d:getetag>"e91f3c9518f76753a7dc5a0cf8998986"</d:getetag>
+ <cal:calendar-data>BEGIN:VCALENDAR
+END:VCALENDAR
+</cal:calendar-data>
+ </d:prop>
+ <d:status>HTTP/1.1 200 OK</d:status>
+ </d:propstat>
+ </d:response>
+ <d:sync-token>http://sabre.io/ns/sync/3</d:sync-token>
+</d:multistatus>
diff --git a/js/dav/test/unit/nock_wrapper.js b/js/dav/test/unit/nock_wrapper.js
new file mode 100644
index 00000000..f665a0ea
--- /dev/null
+++ b/js/dav/test/unit/nock_wrapper.js
@@ -0,0 +1,47 @@
+/**
+ * @fileoverview Decorates nock with some useful utilities.
+ */
+import { assert } from 'chai';
+import co from 'co';
+import nock from 'nock';
+
+export function nockWrapper(url) {
+ let result = nock(url);
+
+ // This is a hack suggested here https://github.com/pgte/nock#protip
+ // to intercept the request conditional on the request body.
+ result.matchRequestBody = (path, method, match, options={}) => {
+ let statusCode = options.statusCode || 200;
+ let statusText = options.statusText || '200 OK';
+ return result
+ .filteringRequestBody(body => match(body) ? '*' : '')
+ .intercept(path, method, '*')
+ .delay(1)
+ .reply(statusCode, statusText);
+ };
+
+ /**
+ * Whether or not an error is thrown in the promise,
+ * the mock should have intercepted the request.
+ */
+ result.verify = co.wrap(function *(promise) {
+ try {
+ yield promise;
+ } catch (error) {
+ assert.notInclude(error.toString(), 'ECONNREFUSED');
+ } finally {
+ result.done();
+ }
+ });
+
+ return result;
+}
+
+Object.keys(nock).forEach(key => {
+ let value = nock[key];
+ if (typeof value !== 'function') {
+ return;
+ }
+
+ nockWrapper[key] = value.bind(nockWrapper)
+});
diff --git a/js/dav/test/unit/parser_test.js b/js/dav/test/unit/parser_test.js
new file mode 100644
index 00000000..bd879d71
--- /dev/null
+++ b/js/dav/test/unit/parser_test.js
@@ -0,0 +1,66 @@
+import { assert } from 'chai';
+
+import { multistatus } from '../../lib/parser';
+import data from './data';
+
+suite('parser.multistatus', function() {
+ test('propfind (current-user-principal)', function() {
+ let currentUserPrincipal = data.currentUserPrincipal;
+ assert.deepEqual(multistatus(currentUserPrincipal), {
+ response: [{
+ href: '/',
+ propstat: [{
+ prop: {
+ currentUserPrincipal: '/principals/admin@domain.tld/'
+ },
+ status: 'HTTP/1.1 200 OK'
+ }]
+ }]
+ });
+ });
+
+ test('report (calendar-query)', function() {
+ let calendarQuery = data.calendarQuery;
+ assert.deepEqual(multistatus(calendarQuery), {
+ response: [
+ {
+ href: '/calendars/johndoe/home/132456762153245.ics',
+ propstat: [{
+ prop: {
+ getetag: '"2134-314"',
+ calendarData: 'BEGIN:VCALENDAR\nEND:VCALENDAR'
+ },
+ status: 'HTTP/1.1 200 OK'
+ }]
+ },
+ {
+ href: '/calendars/johndoe/home/132456-34365.ics',
+ propstat: [{
+ prop: {
+ getetag: '"5467-323"',
+ calendarData: 'BEGIN:VCALENDAR\nEND:VCALENDAR'
+ },
+ status: 'HTTP/1.1 200 OK'
+ }]
+ },
+ ]
+ });
+ });
+
+ test('report (sync-collection)', function() {
+ let syncCollection = data.syncCollection;
+ assert.deepEqual(multistatus(syncCollection), {
+ response: [{
+ href: '/calendars/admin/default/test.ics',
+ propstat: [{
+ prop: {
+ 'calendarData': 'BEGIN:VCALENDAR\nEND:VCALENDAR\n',
+ getetag: '"e91f3c9518f76753a7dc5a0cf8998986"'
+ },
+ status: 'HTTP/1.1 200 OK'
+ }]
+ }],
+ syncToken: 'http://sabre.io/ns/sync/3'
+ });
+ });
+});
diff --git a/js/dav/test/unit/request/address_book_query_test.js b/js/dav/test/unit/request/address_book_query_test.js
new file mode 100644
index 00000000..31777efd
--- /dev/null
+++ b/js/dav/test/unit/request/address_book_query_test.js
@@ -0,0 +1,69 @@
+import { assert } from 'chai';
+import co from 'co';
+
+import * as ns from '../../../lib/namespace';
+import { Request, addressBookQuery } from '../../../lib/request';
+import * as transport from '../../../lib/transport';
+import data from '../data';
+import { nockWrapper } from '../nock_wrapper';
+
+suite('request.addressBookQuery', function() {
+ let xhr;
+
+ setup(function() {
+ xhr = new transport.Basic({ username: 'admin', password: 'admin' });
+ });
+
+ teardown(() => nockWrapper.cleanAll());
+
+ test('should set depth header', co.wrap(function *() {
+ let mock = nockWrapper('http://127.0.0.1:1337')
+ .matchHeader('Depth', 1)
+ .intercept('/principals/admin/', 'REPORT')
+ .reply(200);
+
+ let req = addressBookQuery({
+ props: [ { name: 'address-data', namespace: ns.CARDDAV } ],
+ depth: 1
+ });
+
+ let send = xhr.send(req, 'http://127.0.0.1:1337/principals/admin/');
+ yield mock.verify(send);
+ }));
+
+ test('should add specified props to report body', co.wrap(function *() {
+ let mock = nockWrapper('http://127.0.0.1:1337')
+ .matchRequestBody('/principals/admin/', 'REPORT', body => {
+ return body.indexOf('<d:catdog />') !== -1;
+ });
+
+ let req = addressBookQuery({
+ props: [ { name: 'catdog', namespace: ns.DAV } ]
+ });
+
+ let send = xhr.send(req, 'http://127.0.0.1:1337/principals/admin/');
+ yield mock.verify(send);
+ }));
+
+ test('should resolve with appropriate data structure', co.wrap(function *() {
+ nockWrapper('http://127.0.0.1:1337')
+ .intercept('/', 'REPORT')
+ .reply(200, data.addressBookQuery);
+
+
+ let req = addressBookQuery({
+ props: [
+ { name: 'getetag', namespace: ns.DAV },
+ { name: 'address-data', namespace: ns.CARDDAV }
+ ]
+ });
+
+ let addressBooks = yield xhr.send(req, 'http://127.0.0.1:1337');
+ assert.lengthOf(addressBooks, 2);
+ addressBooks.forEach(addressBook => {
+ assert.typeOf(addressBook.href, 'string');
+ assert.operator(addressBook.href.length, '>', 0);
+ assert.typeOf(addressBook.props, 'object');
+ });
+ }));
+});
diff --git a/js/dav/test/unit/request/basic_test.js b/js/dav/test/unit/request/basic_test.js
new file mode 100644
index 00000000..9ce5f01b
--- /dev/null
+++ b/js/dav/test/unit/request/basic_test.js
@@ -0,0 +1,63 @@
+import { assert } from 'chai';
+import co from 'co';
+
+import { Request, basic } from '../../../lib/request';
+import * as transport from '../../../lib/transport';
+import { nockWrapper } from '../nock_wrapper';
+
+suite('put', function() {
+ let xhr;
+
+ setup(function() {
+ xhr = new transport.Basic({ user: 'admin', password: 'admin' });
+ });
+
+ teardown(() => nockWrapper.cleanAll());
+
+ test('should set If-Match header', co.wrap(function *() {
+ let mock = nockWrapper('http://127.0.0.1:1337')
+ .matchHeader('If-Match', '1337')
+ .intercept('/', 'PUT')
+ .reply(200);
+
+ let req = basic({
+ method: 'PUT',
+ etag: '1337'
+ });
+
+ let send = xhr.send(req, 'http://127.0.0.1:1337');
+ yield mock.verify(send);
+ }));
+
+ test('should send options data as request body', co.wrap(function *() {
+ let mock = nockWrapper('http://127.0.0.1:1337')
+ .matchRequestBody('/', 'PUT', body => {
+ return body === 'Bad hair day!';
+ });
+
+ let req = basic({
+ method: 'PUT',
+ data: 'Bad hair day!'
+ });
+
+ let send = xhr.send(req, 'http://127.0.0.1:1337');
+ yield mock.verify(send);
+ }));
+
+ test('should throw error on bad response', co.wrap(function *() {
+ nockWrapper('http://127.0.0.1:1337')
+ .intercept('/', 'PUT')
+ .delay(1)
+ .reply('400', '400 Bad Request');
+
+ let req = basic({ method: 'PUT' });
+
+ try {
+ yield xhr.send(req, 'http://127.0.0.1:1337')
+ assert.fail('request.basic should have thrown an error');
+ } catch (error) {
+ assert.instanceOf(error, Error);
+ assert.include(error.toString(), 'Bad status: 400');
+ }
+ }));
+});
diff --git a/js/dav/test/unit/request/calendar_query_test.js b/js/dav/test/unit/request/calendar_query_test.js
new file mode 100644
index 00000000..a97e4d0b
--- /dev/null
+++ b/js/dav/test/unit/request/calendar_query_test.js
@@ -0,0 +1,107 @@
+import { assert } from 'chai';
+import co from 'co';
+
+import * as ns from '../../../lib/namespace';
+import { Request, calendarQuery } from '../../../lib/request';
+import * as transport from '../../../lib/transport';
+import data from '../data';
+import { nockWrapper } from '../nock_wrapper';
+
+suite('request.calendarQuery', function() {
+ let xhr;
+
+ setup(function() {
+ xhr = new transport.Basic({ username: 'admin', password: 'admin' });
+ });
+
+ teardown(() => nockWrapper.cleanAll());
+
+ test('should set depth header', co.wrap(function *() {
+ let mock = nockWrapper('http://127.0.0.1:1337')
+ .matchHeader('Depth', 1)
+ .intercept('/principals/admin/', 'REPORT')
+ .reply(200);
+
+ let req = calendarQuery({
+ props: [ { name: 'calendar-data', namespace: ns.CALDAV } ],
+ depth: 1
+ });
+
+ let send = xhr.send(req, 'http://127.0.0.1:1337/principals/admin/');
+ yield mock.verify(send);
+ }));
+
+ test('should add specified props to report body', co.wrap(function *() {