summaryrefslogtreecommitdiffstats
path: root/js/dav/test
diff options
context:
space:
mode:
Diffstat (limited to 'js/dav/test')
-rw-r--r--js/dav/test/integration/accounts_test.js177
-rw-r--r--js/dav/test/integration/calendars_test.js239
-rw-r--r--js/dav/test/integration/contacts_test.js219
-rw-r--r--js/dav/test/integration/data/bastille_day_party.ics12
-rw-r--r--js/dav/test/integration/data/forrest_gump.vcf16
-rw-r--r--js/dav/test/integration/data/index.js17
-rw-r--r--js/dav/test/integration/server/bootstrap.js105
-rw-r--r--js/dav/test/integration/server/calendarserver.php82
-rw-r--r--js/dav/test/integration/version_test.js10
-rw-r--r--js/dav/test/mocha.opts5
-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
29 files changed, 2336 insertions, 0 deletions
diff --git a/js/dav/test/integration/accounts_test.js b/js/dav/test/integration/accounts_test.js
new file mode 100644
index 00000000..7bbb7caf
--- /dev/null
+++ b/js/dav/test/integration/accounts_test.js
@@ -0,0 +1,177 @@
+import { assert } from 'chai';
+import co from 'co';
+
+import * as dav from '../../lib';
+
+suite('accounts', function() {
+ suite('#create', function() {
+ let xhr;
+
+ setup(function() {
+ xhr = new dav.transport.Basic(
+ new dav.Credentials({
+ username: 'admin',
+ password: 'admin'
+ })
+ );
+ });
+
+ test('caldav', co.wrap(function *() {
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888',
+ xhr: xhr,
+ loadObjects: true
+ });
+
+ assert.instanceOf(account, dav.Account);
+ assert.instanceOf(account.credentials, dav.Credentials);
+ assert.strictEqual(account.credentials.username, 'admin');
+ assert.strictEqual(account.credentials.password, 'admin');
+ assert.strictEqual(account.server, 'http://127.0.0.1:8888');
+ assert.strictEqual(account.rootUrl, 'http://127.0.0.1:8888/');
+ assert.strictEqual(
+ account.principalUrl,
+ 'http://127.0.0.1:8888/principals/admin/'
+ );
+ assert.strictEqual(
+ account.homeUrl,
+ 'http://127.0.0.1:8888/calendars/admin/'
+ );
+
+ let calendars = account.calendars;
+ assert.lengthOf(calendars, 1);
+ let calendar = calendars[0];
+ assert.instanceOf(calendar, dav.Calendar);
+ assert.strictEqual(calendar.displayName, 'default calendar');
+ assert.strictEqual(
+ calendar.url,
+ 'http://127.0.0.1:8888/calendars/admin/default/'
+ );
+ assert.strictEqual(calendar.description, 'administrator calendar');
+ assert.include(calendar.components, 'VEVENT');
+ assert.typeOf(calendar.ctag, 'string');
+ assert.isArray(calendar.objects);
+ assert.lengthOf(calendar.objects, 0);
+ assert.isArray(calendar.reports);
+ assert.include(calendar.reports, 'calendar-query');
+ assert.isArray(calendar.resourcetype);
+ assert.include(calendar.resourcetype, 'calendar');
+ assert.typeOf(calendar.syncToken, 'string');
+ assert.operator(calendar.syncToken.length, '>', 0);
+ }));
+
+ test('carddav', co.wrap(function *() {
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888',
+ xhr: xhr,
+ accountType: 'carddav',
+ loadObjects: true
+ });
+
+ assert.instanceOf(account, dav.Account);
+ assert.instanceOf(account.credentials, dav.Credentials);
+ assert.strictEqual(account.credentials.username, 'admin');
+ assert.strictEqual(account.credentials.password, 'admin');
+ assert.strictEqual(account.server, 'http://127.0.0.1:8888');
+ assert.strictEqual(account.rootUrl, 'http://127.0.0.1:8888/');
+ assert.strictEqual(
+ account.principalUrl,
+ 'http://127.0.0.1:8888/principals/admin/'
+ );
+ assert.strictEqual(
+ account.homeUrl,
+ 'http://127.0.0.1:8888/addressbooks/admin/'
+ );
+
+ let addressBooks = account.addressBooks;
+ assert.operator(addressBooks.length, '>', 0);
+ let addressBook = addressBooks[0];
+ assert.instanceOf(addressBook, dav.AddressBook);
+ assert.strictEqual(addressBook.displayName, 'default address book');
+ assert.strictEqual(
+ addressBook.url,
+ 'http://127.0.0.1:8888/addressbooks/admin/default/'
+ );
+ assert.typeOf(addressBook.ctag, 'string');
+ assert.isArray(addressBook.objects);
+ assert.lengthOf(addressBook.objects, 0);
+ assert.isArray(addressBook.reports);
+ assert.include(addressBook.reports, 'addressbook-query');
+ assert.isArray(addressBook.resourcetype);
+ assert.include(addressBook.resourcetype, 'addressbook');
+ assert.typeOf(addressBook.syncToken, 'string');
+ assert.operator(addressBook.syncToken.length, '>', 0);
+ }));
+
+ test('without loading collections', co.wrap(function *() {
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888',
+ xhr: xhr,
+ accountType: 'caldav',
+ loadCollections: false
+ });
+
+ assert.instanceOf(account, dav.Account);
+ assert.instanceOf(account.credentials, dav.Credentials);
+ assert.strictEqual(account.credentials.username, 'admin');
+ assert.strictEqual(account.credentials.password, 'admin');
+ assert.strictEqual(account.server, 'http://127.0.0.1:8888');
+ assert.strictEqual(account.rootUrl, 'http://127.0.0.1:8888/');
+ assert.strictEqual(
+ account.principalUrl,
+ 'http://127.0.0.1:8888/principals/admin/'
+ );
+ assert.strictEqual(
+ account.homeUrl,
+ 'http://127.0.0.1:8888/calendars/admin/'
+ );
+
+ let calendars = account.calendars;
+ assert.notOk(calendars);
+ }));
+
+ test('without loading objects', co.wrap(function *() {
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888',
+ xhr: xhr,
+ accountType: 'caldav',
+ loadObjects: false
+ });
+
+ assert.instanceOf(account, dav.Account);
+ assert.instanceOf(account.credentials, dav.Credentials);
+ assert.strictEqual(account.credentials.username, 'admin');
+ assert.strictEqual(account.credentials.password, 'admin');
+ assert.strictEqual(account.server, 'http://127.0.0.1:8888');
+ assert.strictEqual(account.rootUrl, 'http://127.0.0.1:8888/');
+ assert.strictEqual(
+ account.principalUrl,
+ 'http://127.0.0.1:8888/principals/admin/'
+ );
+ assert.strictEqual(
+ account.homeUrl,
+ 'http://127.0.0.1:8888/calendars/admin/'
+ );
+
+ let calendars = account.calendars;
+ assert.lengthOf(calendars, 1);
+ let calendar = calendars[0];
+ assert.instanceOf(calendar, dav.Calendar);
+ assert.strictEqual(calendar.displayName, 'default calendar');
+ assert.strictEqual(
+ calendar.url,
+ 'http://127.0.0.1:8888/calendars/admin/default/'
+ );
+ assert.strictEqual(calendar.description, 'administrator calendar');
+ assert.include(calendar.components, 'VEVENT');
+ assert.typeOf(calendar.ctag, 'string');
+ assert.notOk(calendar.objects);
+ assert.isArray(calendar.reports);
+ assert.include(calendar.reports, 'calendar-query');
+ assert.isArray(calendar.resourcetype);
+ assert.include(calendar.resourcetype, 'calendar');
+ assert.typeOf(calendar.syncToken, 'string');
+ assert.operator(calendar.syncToken.length, '>', 0);
+ }));
+ });
+});
diff --git a/js/dav/test/integration/calendars_test.js b/js/dav/test/integration/calendars_test.js
new file mode 100644
index 00000000..fddfd04e
--- /dev/null
+++ b/js/dav/test/integration/calendars_test.js
@@ -0,0 +1,239 @@
+import { assert } from 'chai';
+import co from 'co';
+
+import data from './data';
+import * as dav from '../../lib';
+
+let debug = require('../../lib/debug')('dav:calendars_test');
+
+suite('calendars', function() {
+ let calendars, xhr;
+
+ setup(co.wrap(function *() {
+ debug('Create account.');
+ xhr = new dav.transport.Basic(
+ new dav.Credentials({
+ username: 'admin',
+ password: 'admin'
+ })
+ );
+
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888/',
+ xhr: xhr,
+ loadObjects: true
+ });
+
+ let calendar = account.calendars[0];
+ let objects = calendar.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 0, 'initially 0 calendar objects');
+ debug('Create calendar object.');
+ yield dav.createCalendarObject(calendar, {
+ filename: 'test.ics',
+ data: data.bastilleDayParty,
+ xhr: xhr
+ });
+
+ let synced = yield dav.syncCaldavAccount(account, { xhr: xhr });
+ calendars = synced.calendars;
+ }));
+
+ test('#createCalendarObject', function() {
+ let calendar = calendars[0];
+ let objects = calendar.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1);
+ let object = objects[0];
+ assert.instanceOf(object, dav.CalendarObject);
+ assert.instanceOf(object.calendar, dav.Calendar);
+ assert.strictEqual(object.calendarData, data.bastilleDayParty);
+ assert.strictEqual(
+ object.url,
+ 'http://127.0.0.1:8888/calendars/admin/default/test.ics'
+ );
+ });
+
+ test('#updateCalendarObject, #sync', co.wrap(function *() {
+ let calendar = calendars[0];
+ let object = calendar.objects[0];
+ object.calendarData = object.calendarData.replace(
+ 'SUMMARY:Bastille Day Party',
+ 'SUMMARY:Happy Hour'
+ );
+
+ yield dav.updateCalendarObject(object, { xhr: xhr });
+ calendar = yield dav.syncCalendar(calendar, {
+ syncMethod: 'basic',
+ xhr: xhr
+ });
+
+ let objects = calendar.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1, 'update should not create new object');
+ object = objects[0];
+ assert.instanceOf(object, dav.CalendarObject);
+ assert.instanceOf(object.calendar, dav.Calendar);
+ assert.notStrictEqual(
+ object.calendarData,
+ data.bastilleDayParty,
+ 'data should have changed on server'
+ );
+ assert.include(
+ object.calendarData,
+ 'SUMMARY:Happy Hour',
+ 'data should reflect update'
+ );
+ assert.notInclude(
+ object.calendardata,
+ 'SUMMARY:Bastille Day Party',
+ 'data should reflect update'
+ );
+ assert.strictEqual(
+ object.url,
+ 'http://127.0.0.1:8888/calendars/admin/default/test.ics',
+ 'update should not change object url'
+ );
+ }));
+
+ test('webdav sync', co.wrap(function *() {
+ let calendar = calendars[0];
+ let object = calendar.objects[0];
+ object.calendarData = object.calendarData.replace(
+ 'SUMMARY:Bastille Day Party',
+ 'SUMMARY:Happy Hour'
+ );
+
+ let prevEtag = object.etag;
+ assert.typeOf(prevEtag, 'string');
+ assert.operator(prevEtag.length, '>', 0);
+
+ let prevSyncToken = calendar.syncToken;
+ assert.typeOf(prevSyncToken, 'string');
+ assert.operator(prevSyncToken.length, '>', 0);
+
+ yield dav.updateCalendarObject(object, { xhr: xhr });
+ calendar = yield dav.syncCalendar(calendar, {
+ syncMethod: 'webdav',
+ xhr: xhr
+ });
+
+ let objects = calendar.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1, 'update should not create new object');
+
+ object = objects[0];
+ assert.instanceOf(object, dav.CalendarObject);
+ assert.instanceOf(object.calendar, dav.Calendar);
+
+ assert.notStrictEqual(
+ object.calendarData,
+ data.bastilleDayParty,
+ 'data should have changed on server'
+ );
+
+ assert.include(
+ object.calendarData,
+ 'SUMMARY:Happy Hour',
+ 'data should reflect update'
+ );
+
+ assert.notInclude(
+ object.calendardata,
+ 'SUMMARY:Bastille Day Party',
+ 'data should reflect update'
+ );
+
+ assert.strictEqual(
+ object.url,
+ 'http://127.0.0.1:8888/calendars/admin/default/test.ics',
+ 'update should not change object url'
+ );
+
+ assert.typeOf(object.etag, 'string');
+ assert.operator(object.etag.length, '>', 0);
+ assert.notStrictEqual(prevEtag, object.etag, 'new etag');
+
+ assert.typeOf(calendar.syncToken, 'string');
+ assert.operator(calendar.syncToken.length, '>', 0);
+ assert.notStrictEqual(calendar.syncToken, prevSyncToken, 'new token');
+ }));
+
+ test('#deleteCalendarObject', co.wrap(function *() {
+ let calendar = calendars[0];
+ let objects = calendar.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1);
+ let object = objects[0];
+ yield dav.deleteCalendarObject(object, { xhr: xhr });
+ let updated = yield dav.syncCalendar(calendar, {
+ syncMethod: 'basic',
+ xhr: xhr
+ });
+
+ objects = updated.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 0, 'should be deleted');
+ }));
+
+ test('time-range filtering', co.wrap(function *() {
+ let account1 = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888/',
+ loadObjects: true,
+ filters: [{
+ type: 'comp-filter',
+ attrs: { name: 'VCALENDAR' },
+ children: [{
+ type: 'comp-filter',
+ attrs: { name: 'VEVENT' },
+ children: [{
+ type: 'time-range',
+ attrs: { start: '19970714T170000Z' }
+ }]
+ }]
+ }],
+ xhr: xhr
+ });
+
+ assert.lengthOf(account1.calendars[0].objects, 1, 'in range');
+
+ let account2 = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888/',
+ loadObjects: true,
+ filters: [{
+ type: 'comp-filter',
+ attrs: { name: 'VCALENDAR' },
+ children: [{
+ type: 'comp-filter',
+ attrs: { name: 'VEVENT' },
+ children: [{
+ type: 'time-range',
+ attrs: { start: '19980714T170000Z' }
+ }]
+ }]
+ }],
+ xhr: xhr
+ });
+
+ assert.lengthOf(account2.calendars[0].objects, 0, 'out of range');
+ }));
+
+ test('#syncCaldavAccount', co.wrap(function *() {
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888/',
+ xhr: xhr,
+ accountType: 'caldav',
+ loadCollections: false
+ });
+ assert.instanceOf(account, dav.Account);
+ assert.notOk(account.calendars);
+
+ account = yield dav.syncCaldavAccount(account, { xhr: xhr });
+ assert.instanceOf(account, dav.Account);
+ assert.isArray(account.calendars);
+ assert.lengthOf(account.calendars, 1);
+ let calendar = account.calendars[0];
+ assert.instanceOf(calendar, dav.Calendar);
+ assert.strictEqual(calendar.displayName, 'default calendar');
+ }));
+});
diff --git a/js/dav/test/integration/contacts_test.js b/js/dav/test/integration/contacts_test.js
new file mode 100644
index 00000000..3995e0ca
--- /dev/null
+++ b/js/dav/test/integration/contacts_test.js
@@ -0,0 +1,219 @@
+import { assert } from 'chai';
+import co from 'co';
+
+import data from './data';
+import * as dav from '../../lib';
+
+let debug = require('../../lib/debug')('dav:contacts_test');
+
+suite('contacts', function() {
+ let addressBooks, xhr;
+
+ setup(co.wrap(function *() {
+ debug('Create account.');
+
+ xhr = new dav.transport.Basic(
+ new dav.Credentials({
+ username: 'admin',
+ password: 'admin'
+ })
+ );
+
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888/',
+ xhr: xhr,
+ accountType: 'carddav',
+ loadObjects: true
+ });
+
+ let addressBook = account.addressBooks[0];
+ let objects = addressBook.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 0, 'initially 0 address books');
+
+ debug('Create vcard.');
+ yield dav.createCard(addressBook, {
+ filename: 'test.vcf',
+ data: data.forrestGump,
+ xhr: xhr
+ });
+
+ let updated = yield dav.syncCarddavAccount(account, {
+ syncMethod: 'basic',
+ xhr: xhr
+ });
+
+ addressBooks = updated.addressBooks;
+ }));
+
+ test('#createCard', function() {
+ let addressBook = addressBooks[0];
+ let objects = addressBook.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1);
+ let object = objects[0];
+ assert.instanceOf(object, dav.VCard);
+ assert.instanceOf(object.addressBook, dav.AddressBook);
+ assert.strictEqual(
+ object.addressData
+ .replace(/UID\:[^\n]+\n/, '')
+ .replace(/;/g, '')
+ .replace(/\s+/g, ''),
+ data.forrestGump
+ .replace(/;/g, '')
+ .replace(/\s+/g, '')
+ );
+ assert.strictEqual(
+ object.url,
+ 'http://127.0.0.1:8888/addressbooks/admin/default/test.vcf'
+ );
+ });
+
+ test('#updateCard, #sync', co.wrap(function *() {
+ let addressBook = addressBooks[0];
+ let object = addressBook.objects[0];
+ object.addressData = object.addressData.replace(
+ 'forrestgump@example.com',
+ 'lieutenantdan@example.com'
+ );
+
+ yield dav.updateCard(object, { xhr: xhr });
+ let updated = yield dav.syncAddressBook(addressBook, {
+ syncMethod: 'basic',
+ xhr: xhr
+ });
+
+ let objects = updated.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1, 'update should not create new object');
+ object = objects[0];
+ assert.instanceOf(object, dav.VCard);
+ assert.instanceOf(object.addressBook, dav.AddressBook);
+ assert.notStrictEqual(
+ object.addressData
+ .replace(/UID\:[^\n]+\n/, '')
+ .replace(/;/g, '')
+ .replace(/\s+/g, ''),
+ data.forrestGump
+ .replace(/;/g, '')
+ .replace(/\s+/g, ''),
+ 'data should have changed on server'
+ );
+ assert.include(
+ object.addressData,
+ 'lieutenantdan@example.com',
+ 'data should reflect update'
+ );
+ assert.notInclude(
+ object.addressData,
+ 'forrestgump@example.com',
+ 'data should reflect update'
+ );
+ assert.strictEqual(
+ object.url,
+ 'http://127.0.0.1:8888/addressbooks/admin/default/test.vcf',
+ 'update should not change object url'
+ );
+ }));
+
+ test('webdav sync', co.wrap(function *() {
+ let addressBook = addressBooks[0];
+ let object = addressBook.objects[0];
+ object.addressData = object.addressData.replace(
+ 'forrestgump@example.com',
+ 'lieutenantdan@example.com'
+ );
+
+ let prevEtag = object.etag;
+ assert.typeOf(prevEtag, 'string');
+ assert.operator(prevEtag.length, '>', 0);
+
+ let prevSyncToken = addressBook.syncToken;
+ assert.typeOf(prevSyncToken, 'string');
+ assert.operator(prevSyncToken.length, '>', 0);
+
+ yield dav.updateCard(object, { xhr: xhr });
+ let updated = yield dav.syncAddressBook(addressBook, {
+ syncMethod: 'webdav',
+ xhr: xhr
+ });
+
+ let objects = updated.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1, 'update should not create new object');
+
+ object = objects[0];
+ assert.instanceOf(object, dav.VCard);
+ assert.instanceOf(object.addressBook, dav.AddressBook);
+
+ assert.notStrictEqual(
+ object.addressData
+ .replace(/UID\:[^\n]+\n/, '')
+ .replace(/;/g, '')
+ .replace(/\s+/g, ''),
+ data.forrestGump
+ .replace(/;/g, '')
+ .replace(/\s+/g, ''),
+ 'data should have changed on server'
+ );
+ assert.include(
+ object.addressData,
+ 'lieutenantdan@example.com',
+ 'data should reflect update'
+ );
+ assert.notInclude(
+ object.addressData,
+ 'forrestgump@example.com',
+ 'data should reflect update'
+ );
+ assert.notStrictEqual(
+ object.addressData,
+ data.bastilleDayParty,
+ 'data should have changed on server'
+ );
+
+ assert.typeOf(object.etag, 'string');
+ assert.operator(object.etag.length, '>', 0);
+ assert.notStrictEqual(prevEtag, object.etag, 'new etag');
+
+ assert.typeOf(addressBook.syncToken, 'string');
+ assert.operator(addressBook.syncToken.length, '>', 0);
+ assert.notStrictEqual(addressBook.syncToken, prevSyncToken, 'new token');
+ }));
+
+ test('#deleteCard', co.wrap(function *() {
+ let addressBook = addressBooks[0];
+ let objects = addressBook.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 1);
+ let object = objects[0];
+ yield dav.deleteCard(object, { xhr: xhr });
+ let updated = yield dav.syncAddressBook(addressBook, {
+ syncMethod: 'basic',
+ xhr: xhr
+ });
+
+ objects = addressBook.objects;
+ assert.isArray(objects);
+ assert.lengthOf(objects, 0, 'should be deleted');
+ }));
+
+ test('#syncCarddavAccount', co.wrap(function *() {
+ let account = yield dav.createAccount({
+ server: 'http://127.0.0.1:8888/',
+ xhr: xhr,
+ accountType: 'carddav',
+ loadCollections: false
+ });
+
+ assert.instanceOf(account, dav.Account);
+ assert.notOk(account.addressBooks);
+ let updated = yield dav.syncCarddavAccount(account, { xhr: xhr });
+ assert.instanceOf(updated, dav.Account);
+ assert.isArray(updated.addressBooks);
+ assert.lengthOf(updated.addressBooks, 1);
+ let addressBook = addressBooks[0];
+ assert.instanceOf(addressBook, dav.AddressBook);
+ assert.strictEqual(addressBook.displayName, 'default address book');
+ }));
+});
diff --git a/js/dav/test/integration/data/bastille_day_party.ics b/js/dav/test/integration/data/bastille_day_party.ics
new file mode 100644
index 00000000..46df0673
--- /dev/null
+++ b/js/dav/test/integration/data/bastille_day_party.ics
@@ -0,0 +1,12 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//hacksw/handcal//NONSGML v1.0//EN
+BEGIN:VEVENT
+UID:uid1@example.com
+DTSTAMP:19970714T170000Z
+ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
+DTSTART:19970714T170000Z
+DTEND:19970715T035959Z
+SUMMARY:Bastille Day Party
+END:VEVENT
+END:VCALENDAR
diff --git a/js/dav/test/integration/data/forrest_gump.vcf b/js/dav/test/integration/data/forrest_gump.vcf
new file mode 100644
index 00000000..82ec31d5
--- /dev/null
+++ b/js/dav/test/integration/data/forrest_gump.vcf
@@ -0,0 +1,16 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Gump;Forrest;Mr.
+FN:Forrest Gump
+ORG:Bubba Gump Shrimp Co.
+TITLE:Shrimp Man
+PHOTO;VALUE=URL;TYPE=GIF:http://www.example.com/dir_photos/my_photo.gif
+TEL;TYPE=WORK,VOICE:(111) 555-12121
+TEL;TYPE=HOME,VOICE:(404) 555-1212
+ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
+LABEL;TYPE=WORK:100 Waters Edge\nBaytown, LA 30314\nUnited States of America
+ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
+LABEL;TYPE=HOME:42 Plantation St.\nBaytown, LA 30314\nUnited States of America
+EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com
+REV:2008-04-24T19:52:43Z
+END:VCARD
diff --git a/js/dav/test/integration/data/index.js b/js/dav/test/integration/data/index.js
new file mode 100644
index 00000000..7d2ed03b
--- /dev/null
+++ b/js/dav/test/integration/data/index.js
@@ -0,0 +1,17 @@
+import camelize from '../../../lib/camelize';
+import { format } from 'util';
+import fs from 'fs';
+
+let docs = {};
+export default docs;
+
+[
+ { name: 'bastille_day_party', fmt: 'ics' },
+ { name: 'forrest_gump', fmt: 'vcf' }
+].forEach(function(file) {
+ let camelCase = camelize(file.name);
+ docs[camelCase] = fs.readFileSync(
+ format('%s/%s.%s', __dirname, file.name, file.fmt),
+ 'utf-8'
+ );
+});
diff --git a/js/dav/test/integration/server/bootstrap.js b/js/dav/test/integration/server/bootstrap.js
new file mode 100644
index 00000000..32187565
--- /dev/null
+++ b/js/dav/test/integration/server/bootstrap.js
@@ -0,0 +1,105 @@
+import { format } from 'util';
+import { exec, spawn } from 'child_process';
+import tcpPortUsed from 'tcp-port-used';
+
+let debug = require('../../../lib/debug')('dav:test:bootstrap');
+
+let calendarData = {
+ table: 'calendars',
+ data: {
+ principaluri: 'principals/admin',
+ displayname: 'default calendar',
+ uri: 'default',
+ description: 'administrator calenda